Browse Source

Testcases for direct .call/.apply handling

pull/1421/head
Sami Vaarala 8 years ago
parent
commit
0394a4f280
  1. 91
      tests/ecmascript/test-bi-function-call-apply-bind-combinations.js
  2. 33
      tests/ecmascript/test-bi-function-proto-apply-hugeargs.js
  3. 30
      tests/ecmascript/test-bi-function-proto-apply-tail.js
  4. 36
      tests/ecmascript/test-bi-function-proto-call-hugeargs.js
  5. 30
      tests/ecmascript/test-bi-function-proto-call-tail.js
  6. 30
      tests/ecmascript/test-bi-reflect-apply-tail.js
  7. 40
      tests/ecmascript/test-dev-call-apply-not-in-callstack.js
  8. 111
      tests/ecmascript/test-dev-func-call-apply-missing-args.js
  9. 84
      tests/ecmascript/test-dev-func-call-apply-no-native-stack.js
  10. 17
      tests/ecmascript/test-dev-yield-after-callapply.js

91
tests/ecmascript/test-bi-function-call-apply-bind-combinations.js

@ -0,0 +1,91 @@
/*
* Test that .bind(), .call(), and .apply() can be used in various
* combinations.
*/
/*===
[object global] 1 2 3 undefined undefined undefined undefined undefined undefined undefined
arguments: 3 1 2 3 undefined undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 102 undefined undefined undefined undefined undefined undefined undefined undefined
arguments: 2 101 102 undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 102 103 undefined undefined undefined undefined undefined undefined undefined
arguments: 3 101 102 103 undefined undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 102 103 104 undefined undefined undefined undefined undefined undefined
arguments: 4 101 102 103 104 undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 102 103 104 105 undefined undefined undefined undefined undefined
arguments: 5 101 102 103 104 105 undefined undefined undefined undefined undefined undefined undefined
mythis 101 102 103 104 105 106 undefined undefined undefined undefined
arguments: 6 101 102 103 104 105 106 undefined undefined undefined undefined undefined undefined
mythis 101 102 103 104 105 106 107 undefined undefined undefined
arguments: 7 101 102 103 104 105 106 107 undefined undefined undefined undefined undefined
boundcallthis 201 202 303 304 undefined undefined undefined undefined undefined undefined
arguments: 4 201 202 303 304 undefined undefined undefined undefined undefined undefined undefined undefined
boundcallthis 201 202 303 304 undefined undefined undefined undefined undefined undefined
arguments: 4 201 202 303 304 undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 202 203 304 305 undefined undefined undefined undefined undefined
arguments: 5 101 202 203 304 305 undefined undefined undefined undefined undefined undefined undefined
mythis 101 202 203 304 305 undefined undefined undefined undefined undefined
arguments: 5 101 202 203 304 305 undefined undefined undefined undefined undefined undefined undefined
boundapplythis 201 202 undefined undefined undefined undefined undefined undefined undefined undefined
arguments: 2 201 202 undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined
boundapplythis 201 202 undefined undefined undefined undefined undefined undefined undefined undefined
arguments: 2 201 202 undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 202 203 undefined undefined undefined undefined undefined undefined undefined
arguments: 3 101 202 203 undefined undefined undefined undefined undefined undefined undefined undefined undefined
mythis 101 202 203 undefined undefined undefined undefined undefined undefined undefined
arguments: 3 101 202 203 undefined undefined undefined undefined undefined undefined undefined undefined undefined
===*/
function test() {
var f0 = function f0(a, b, c, d, e, f, g, h, i, j) {
print(this, a, b, c, d, e, f, g, h, i, j);
print('arguments:', arguments.length,
arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4], arguments[5], arguments[6], arguments[7],
arguments[8], arguments[9], arguments[10], arguments[11]);
};
// Direct call.
f0(1, 2, 3);
// Bound call.
var f1 = f0.bind('mythis', 101);
f1(102);
// Bound call, call via .call().
f1.call('callthis', 102, 103);
// Bound call, call via .call(); but use .apply() to call .call().
f1.call.apply(f1, [ 'callthis', 102, 103, 104 ]);
// Bound call, call via .apply().
f1.apply('applythis', [ 102, 103, 104, 105 ]);
// Bound call, call via .apply(); but use .call() to call .apply().
f1.apply.call(f1, 'applythis', [ 102, 103, 104, 105, 106 ]);
// Bound call, call via .apply(); but use .apply() to call .apply().
f1.apply.apply(f1, [ 'applythis', [ 102, 103, 104, 105, 106, 107 ] ]);
// Use .bind() on .call().
var f2 = f0.call.bind(f0, 'boundcallthis', 201, 202);
f2(303, 304);
f2.call('ignored', 303, 304);
var f3 = f1.call.bind(f1, 'boundcallthis', 202, 203);
f3(304, 305);
f3.apply('ignored', [ 304, 305 ]);
// Use .bind() on .apply().
var f4 = f0.apply.bind(f0, 'boundapplythis', [ 201, 202 ]);
f4(303, 304);
f4.call('ignored', 303, 304); // these args get ignored because they don't affect [ 201, 202 ]
var f5 = f1.apply.bind(f1, 'boundapplythis', [ 202, 203 ]);
f5(304, 305);
f5.apply('ignored', [ 304, 305 ]); // same here, [ 304, 305 ] is ignored by .apply()
}
try {
test();
} catch (e) {
print(e.stack || e);
}

33
tests/ecmascript/test-bi-function-proto-apply-hugeargs.js

@ -0,0 +1,33 @@
/*===
f0 called
applythis arg-0 arg-1 arg-2
500000
arg-499998
arg-499999
undefined
done
===*/
function test() {
function f0(a, b, c) {
print('f0 called');
print(this, a, b, c);
print(arguments.length);
print(arguments[499998]);
print(arguments[499999]);
print(arguments[500000]);
}
var args = [];
while (args.length < 500000) {
args.push('arg-' + args.length);
}
f0.apply('applythis', args);
print('done');
}
try {
test();
} catch (e) {
print(e.stack || e);
}

30
tests/ecmascript/test-bi-function-proto-apply-tail.js

@ -0,0 +1,30 @@
/*===
0
100000
200000
300000
400000
500000
600000
700000
800000
900000
1000000
done
===*/
function test(count) {
if ((count % 1e5) == 0) {
print(count);
}
if (count < 1e6) {
return test.apply(null, [ count + 1 ]);
}
return 'done';
}
try {
print(test(0));
} catch (e) {
print(e.stack || e);
}

36
tests/ecmascript/test-bi-function-proto-call-hugeargs.js

@ -0,0 +1,36 @@
/*===
f0 called
callthis arg-0 arg-1 arg-2
500000
arg-499998
arg-499999
undefined
done
===*/
function test() {
function f0(a, b, c) {
print('f0 called');
print(this, a, b, c);
print(arguments.length);
print(arguments[499998]);
print(arguments[499999]);
print(arguments[500000]);
}
var args = [];
while (args.length < 500000) {
args.push('arg-' + args.length);
}
args.unshift('callthis');
// Call .call() via .apply() to ensure huge argument count makes it.
f0.call.apply(f0, args);
print('done');
}
try {
test();
} catch (e) {
print(e.stack || e);
}

30
tests/ecmascript/test-bi-function-proto-call-tail.js

@ -0,0 +1,30 @@
/*===
0
100000
200000
300000
400000
500000
600000
700000
800000
900000
1000000
done
===*/
function test(count) {
if ((count % 1e5) == 0) {
print(count);
}
if (count < 1e6) {
return test.call(null, count + 1);
}
return 'done';
}
try {
print(test(0));
} catch (e) {
print(e.stack || e);
}

30
tests/ecmascript/test-bi-reflect-apply-tail.js

@ -0,0 +1,30 @@
/*===
0
100000
200000
300000
400000
500000
600000
700000
800000
900000
1000000
done
===*/
function test(count) {
if ((count % 1e5) == 0) {
print(count);
}
if (count < 1e6) {
return Reflect.apply(test, null, [ count + 1 ]);
}
return 'done';
}
try {
print(test(0));
} catch (e) {
print(e.stack || e);
}

40
tests/ecmascript/test-dev-call-apply-not-in-callstack.js

@ -0,0 +1,40 @@
/*
* Since Duktape 2.2 .call() and .apply() no longer visible in call stack.
*/
/*===
f0 called
-1 act
-2 f0
-3 f1
-4 f2
-5 f3
-6 test
-7 global
===*/
function test() {
var f0 = function f0() {
print('f0 called');
for (var i = -1; ; i--) {
var act = Duktape.act(i);
if (!act) { break; }
print(i, act.function.name);
}
};
var f1 = function f1() {
Reflect.apply(f0, 'dummy');
}
var f2 = function f2() {
f1.call('dummy');
}
var f3 = function f3() {
f2.apply('dummy');
}
f3();
}
try {
test();
} catch (e) {
print(e.stack || e);
}

111
tests/ecmascript/test-dev-func-call-apply-missing-args.js

@ -0,0 +1,111 @@
/*
* Some tests for .call() and .apply() with missing arguments.
*/
/*===
- Function.prototype.call()
undefined undefined undefined undefined
mythis undefined undefined undefined
mythis arg undefined undefined
- Function.prototype.apply()
undefined undefined undefined undefined
mythis undefined undefined undefined
mythis undefined undefined undefined
mythis undefined undefined undefined
mythis undefined undefined undefined
mythis arg undefined undefined
mythis undefined undefined undefined
mythis foo bar undefined
mythis FOO BAR undefined
TypeError
- Reflect.apply()
TypeError
TypeError
undefined undefined undefined undefined
mythis undefined undefined undefined
mythis undefined undefined undefined
mythis undefined undefined undefined
mythis undefined undefined undefined
mythis arg undefined undefined
mythis undefined undefined undefined
mythis foo bar undefined
mythis FOO BAR undefined
TypeError
done
===*/
function test() {
function func(a,b,c) {
'use strict'; // avoid 'this' coercion
print(this, a, b, c);
}
var dummyFunc = function dummy(a,b) {}; // length: 2
dummyFunc[0] = 'FOO';
dummyFunc[1] = 'BAR';
dummyFunc[2] = 'QUUX';
// For .call() there are no required arguments.
// This binding will be 'undefined'.
print('- Function.prototype.call()');
func.call();
func.call('mythis');
func.call('mythis', 'arg');
// For .apply() there are similarly no required arguments.
// argArray can be null/undefined and is treated like empty
// array. Array-like object is accepted (.length is respected);
// other types cause a TypeError. A function is an acceptable
// input because it's an object and even has a .length!
print('- Function.prototype.apply()');
func.apply();
func.apply('mythis');
func.apply('mythis', void 0);
func.apply('mythis', null);
func.apply('mythis', []);
func.apply('mythis', [ 'arg' ]);
func.apply('mythis', {}); // no .length -> same as []
func.apply('mythis', { length: 2, 0: 'foo', 1: 'bar', 2: 'quux-ignored' });
func.apply('mythis', dummyFunc);
try {
func.apply('mythis', 123);
} catch (e) {
print(e.name);
}
// Reflect.apply() requires a callable first argument,
// but is otherwise similar to Function.prototype.apply().
print('- Reflect.apply()');
try {
Reflect.apply();
} catch (e) {
print(e.name);
}
try {
Reflect.apply(123);
} catch (e) {
print(e.name);
}
Reflect.apply(func);
Reflect.apply(func, 'mythis');
Reflect.apply(func, 'mythis', void 0);
Reflect.apply(func, 'mythis', null);
Reflect.apply(func, 'mythis', []);
Reflect.apply(func, 'mythis', [ 'arg' ]);
Reflect.apply(func, 'mythis', {});
Reflect.apply(func, 'mythis', { length: 2, 0: 'foo', 1: 'bar', 2: 'quux-ignored' });
Reflect.apply(func, 'mythis', dummyFunc);
try {
Reflect.apply(func, 'mythis', 123);
} catch (e) {
print(e.name);
}
print('done');
}
try {
test();
} catch (e) {
print(e.stack || e);
}

84
tests/ecmascript/test-dev-func-call-apply-no-native-stack.js

@ -0,0 +1,84 @@
/*
* Demonstrate that in Duktape 2.2 .call() and .apply() no longer
* consume native call stack when the resolved call is an Ecma-to-Ecma
* call.
*
* Can't test against a specific limit but the native stack limit is
* ~500 calls while the default call stack limit is ~10000 calls.
*/
/*===
RangeError
true
RangeError
true
RangeError
true
RangeError
true
done
===*/
function test() {
var count;
function f1() {
count++;
f1(); // not a tail call
void count;
}
function f2() {
count++;
f2.call(); // not a tail call
void count;
}
function f3() {
count++;
f3.apply(); // not a tail call
void count;
}
function f4() {
count++;
Reflect.apply(f4); // not a tail call
void count;
}
try {
count = 0;
f1();
} catch (e) {
print(e.name);
}
print(count > 2000);
try {
count = 0;
f2();
} catch (e) {
print(e.name);
}
print(count > 2000);
try {
count = 0;
f3();
} catch (e) {
print(e.name);
}
print(count > 2000);
try {
count = 0;
f4();
} catch (e) {
print(e.name);
}
print(count > 2000);
print('done');
}
try {
test();
} catch (e) {
print(e.stack || e);
}

17
tests/ecmascript/test-dev-yield-after-callapply.js

@ -10,10 +10,11 @@ var res;
/*===
123
123
123
===*/
/* Calling via Function.prototype.call() or Function.prototype.apply()
* currently prevents a yield.
* no longer prevents a yield in Duktape 2.2.
*/
function innerfunc() {
@ -21,15 +22,17 @@ function innerfunc() {
}
function coroutine1() {
// This is a native call so the current (naive) handling prevents a later yield
innerfunc.call();
}
function coroutine2() {
// Same here
innerfunc.apply();
}
function coroutine3() {
Reflect.apply(innerfunc);
}
try {
thread = new Duktape.Thread(coroutine1);
res = Duktape.Thread.resume(thread, 0);
@ -45,3 +48,11 @@ try {
} catch (e) {
print(e.name);
}
try {
thread = new Duktape.Thread(coroutine3);
res = Duktape.Thread.resume(thread, 0);
print(res);
} catch (e) {
print(e.name);
}

Loading…
Cancel
Save