mirror of https://github.com/svaarala/duktape.git
Sami Vaarala
8 years ago
committed by
GitHub
26 changed files with 841 additions and 174 deletions
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -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); |
|||
} |
@ -0,0 +1,30 @@ |
|||
if (typeof print !== 'function') { print = console.log; } |
|||
|
|||
function target(x) { |
|||
} |
|||
|
|||
function test() { |
|||
var f = target; |
|||
var i; |
|||
var args = [ 123 ]; |
|||
|
|||
for (i = 0; i < 1e6; i++) { |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
target.apply(null, args); |
|||
} |
|||
} |
|||
|
|||
try { |
|||
test(); |
|||
} catch (e) { |
|||
print(e.stack || e); |
|||
throw e; |
|||
} |
@ -0,0 +1,29 @@ |
|||
if (typeof print !== 'function') { print = console.log; } |
|||
|
|||
function target(x) { |
|||
} |
|||
|
|||
function test() { |
|||
var f = target; |
|||
var i; |
|||
|
|||
for (i = 0; i < 1e6; i++) { |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
target.call(null, 123); |
|||
} |
|||
} |
|||
|
|||
try { |
|||
test(); |
|||
} catch (e) { |
|||
print(e.stack || e); |
|||
throw e; |
|||
} |
Loading…
Reference in new issue