mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
532 lines
11 KiB
532 lines
11 KiB
/*
|
|
* Development test for avoiding relying on a register bound variable
|
|
* as a final expression result for assignment: it's incorrect if the
|
|
* value is used as an input for further expressions because it may
|
|
* change before it's eventually read.
|
|
*
|
|
* Exercise all code paths of duk_js_compiler 'assign:' handling.
|
|
* Generated bytecode should also be inspected manually using e.g.
|
|
* the debugger web UI.
|
|
*/
|
|
|
|
/*===
|
|
slow path
|
|
true
|
|
123
|
|
123.1
|
|
5
|
|
99
|
|
100
|
|
223
|
|
346.1
|
|
351.1
|
|
450.1
|
|
true
|
|
123
|
|
123.1
|
|
5
|
|
99
|
|
100
|
|
223
|
|
346.1
|
|
351.1
|
|
450.1
|
|
post: true
|
|
post: 123
|
|
post: 123.1
|
|
post: 5
|
|
post: 99
|
|
post: 100
|
|
post: 223
|
|
post: 346.1
|
|
post: 351.1
|
|
post: 450.1
|
|
pre: 450.1
|
|
post: true
|
|
pre: true
|
|
post: 123
|
|
pre: 123
|
|
post: 123.1
|
|
pre: 123.1
|
|
post: 5
|
|
pre: 5
|
|
post: 99
|
|
pre: 99
|
|
post: 100
|
|
pre: 100
|
|
post: 223
|
|
pre: 223
|
|
post: 346.1
|
|
pre: 346.1
|
|
post: 351.1
|
|
pre: 351.1
|
|
post: 450.1
|
|
true
|
|
true
|
|
123
|
|
123
|
|
123.1
|
|
123.1
|
|
5
|
|
5
|
|
99
|
|
99
|
|
100
|
|
100
|
|
223
|
|
223
|
|
346.1
|
|
346.1
|
|
351.1
|
|
351.1
|
|
450.1
|
|
450.1
|
|
100
|
|
100
|
|
600
|
|
1000
|
|
100
|
|
650
|
|
30
|
|
100
|
|
3
|
|
3
|
|
arg1
|
|
arg2
|
|
357
|
|
30
|
|
100
|
|
===*/
|
|
|
|
var glob;
|
|
|
|
/* Test assignment cases where LHS is handled using slow path PUTVAR. */
|
|
|
|
function slowPathAssignTest() {
|
|
var four = 4;
|
|
var y = 99;
|
|
var y1 = 10;
|
|
var y2 = 20;
|
|
var y3 = 30;
|
|
var y4 = 40;
|
|
|
|
// Top-level assignment cases.
|
|
// plain: true, 123
|
|
// const: 123.1, 'foo'
|
|
// temp reg: four + 1
|
|
// reg-bound var: y
|
|
|
|
glob = true; print(glob);
|
|
glob = 123; print(glob);
|
|
glob = 123.1; print(glob);
|
|
glob = four + 1; print(glob);
|
|
glob = y; print(glob);
|
|
|
|
glob += true; print(glob);
|
|
glob += 123; print(glob);
|
|
glob += 123.1; print(glob);
|
|
glob += four + 1; print(glob);
|
|
glob += y; print(glob);
|
|
|
|
// Parenthesis don't affect the top level status.
|
|
|
|
(glob = true); print(glob);
|
|
(glob = 123); print(glob);
|
|
(glob = 123.1); print(glob);
|
|
(glob = four + 1); print(glob);
|
|
(glob = y); print(glob);
|
|
|
|
(glob += true); print(glob);
|
|
(glob += 123); print(glob);
|
|
(glob += 123.1); print(glob);
|
|
(glob += four + 1); print(glob);
|
|
(glob += y); print(glob);
|
|
|
|
// Comma expression doesn't affect top level status.
|
|
|
|
glob = true, print('post: ' + glob);
|
|
glob = 123, print('post: ' + glob);
|
|
glob = 123.1, print('post: ' + glob);
|
|
glob = four + 1, print('post: ' + glob);
|
|
glob = y, print('post: ' + glob);
|
|
|
|
glob += true, print('post: ' + glob);
|
|
glob += 123, print('post: ' + glob);
|
|
glob += 123.1, print('post: ' + glob);
|
|
glob += four + 1, print('post: ' + glob);
|
|
glob += y, print('post: ' + glob);
|
|
|
|
print('pre: ' + glob), glob = true, print('post: ' + glob);
|
|
print('pre: ' + glob), glob = 123, print('post: ' + glob);
|
|
print('pre: ' + glob), glob = 123.1, print('post: ' + glob);
|
|
print('pre: ' + glob), glob = four + 1, print('post: ' + glob);
|
|
print('pre: ' + glob), glob = y, print('post: ' + glob);
|
|
|
|
print('pre: ' + glob), glob += true, print('post: ' + glob);
|
|
print('pre: ' + glob), glob += 123, print('post: ' + glob);
|
|
print('pre: ' + glob), glob += 123.1, print('post: ' + glob);
|
|
print('pre: ' + glob), glob += four + 1, print('post: ' + glob);
|
|
print('pre: ' + glob), glob += y, print('post: ' + glob);
|
|
|
|
// Being inside a function call (or any other expression type)
|
|
// removes top level status.
|
|
|
|
print(glob = true); print(glob);
|
|
print(glob = 123); print(glob);
|
|
print(glob = 123.1); print(glob);
|
|
print(glob = four + 1); print(glob);
|
|
print(glob = y); print(glob);
|
|
|
|
print(glob += true); print(glob);
|
|
print(glob += 123); print(glob);
|
|
print(glob += 123.1); print(glob);
|
|
print(glob += four + 1); print(glob);
|
|
print(glob += y); print(glob);
|
|
|
|
// Intermediate values must be independent of 'glob'.
|
|
|
|
print( ((glob = 10) + (glob = 20)) + ((glob = 30) + (glob = 40)) );
|
|
print( ((glob = y1) + (glob = y2)) + ((glob = y3) + (glob = y4)) );
|
|
|
|
glob = 100;
|
|
print( ((glob += 10) + (glob += 20)) + ((glob += 30) + (glob += 40)) );
|
|
print( ((glob += y1) + (glob += y2)) + ((glob += y3) + (glob += y4)) );
|
|
|
|
// Both LHS and RHS are mutated so an actual temp is mandatory.
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( ((glob = y1) + (glob = y1 = y2)) + ((glob = y1 = y2 = y3) + (glob = y1 = y2 = y3 = y4)) );
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( ((glob += y1) + (glob += y1 += y2)) + ((glob += y1 += y2 += y3) + (glob += y1 += y2 += y3 += y4)) );
|
|
|
|
// Unresolved addition as RHS.
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
glob = y1 + y2; print(glob);
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( (glob = y1 + y2) + (glob = y3 + y4) );
|
|
|
|
// Unresolved addition as RHS. Must be computed exactly once
|
|
// so that side effects are not repeated.
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print(glob = 1 + 2); print(glob);
|
|
|
|
var obj1 = {valueOf: function() { print('arg1'); return 123; }};
|
|
var obj2 = {valueOf: function() { print('arg2'); return 234; }};
|
|
print(glob = obj1 + obj2);
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
glob = y1 + y2; print(glob);
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( (glob = y1 + y2) + (glob = y3 + y4) );
|
|
}
|
|
|
|
try {
|
|
print('slow path');
|
|
slowPathAssignTest();
|
|
} catch (e) {
|
|
print(e.stack || e);
|
|
}
|
|
|
|
/*===
|
|
fast path
|
|
true
|
|
123
|
|
123.1
|
|
5
|
|
99
|
|
100
|
|
223
|
|
346.1
|
|
351.1
|
|
450.1
|
|
true
|
|
123
|
|
123.1
|
|
5
|
|
99
|
|
100
|
|
223
|
|
346.1
|
|
351.1
|
|
450.1
|
|
post: true
|
|
post: 123
|
|
post: 123.1
|
|
post: 5
|
|
post: 99
|
|
post: 100
|
|
post: 223
|
|
post: 346.1
|
|
post: 351.1
|
|
post: 450.1
|
|
pre: 450.1
|
|
post: true
|
|
pre: true
|
|
post: 123
|
|
pre: 123
|
|
post: 123.1
|
|
pre: 123.1
|
|
post: 5
|
|
pre: 5
|
|
post: 99
|
|
pre: 99
|
|
post: 100
|
|
pre: 100
|
|
post: 223
|
|
pre: 223
|
|
post: 346.1
|
|
pre: 346.1
|
|
post: 351.1
|
|
pre: 351.1
|
|
post: 450.1
|
|
true
|
|
true
|
|
123
|
|
123
|
|
123.1
|
|
123.1
|
|
5
|
|
5
|
|
99
|
|
99
|
|
100
|
|
100
|
|
223
|
|
223
|
|
346.1
|
|
346.1
|
|
351.1
|
|
351.1
|
|
450.1
|
|
450.1
|
|
100
|
|
100
|
|
600
|
|
1000
|
|
100
|
|
650
|
|
3
|
|
3
|
|
arg1
|
|
arg2
|
|
357
|
|
30
|
|
100
|
|
===*/
|
|
|
|
/* Test assignment cases where LHS is handled using the fast path, i.e.
|
|
* a register load to a register-bound identifier.
|
|
*/
|
|
|
|
function fastPathAssignTest() {
|
|
var four = 4;
|
|
var x;
|
|
var y = 99;
|
|
var y1 = 10;
|
|
var y2 = 20;
|
|
var y3 = 30;
|
|
var y4 = 40;
|
|
|
|
// Top-level assignment cases.
|
|
// plain: true, 123
|
|
// const: 123.1, 'foo'
|
|
// temp reg: four + 1
|
|
// reg-bound var: y
|
|
|
|
x = true; print(x);
|
|
x = 123; print(x);
|
|
x = 123.1; print(x);
|
|
x = four + 1; print(x);
|
|
x = y; print(x);
|
|
|
|
x += true; print(x);
|
|
x += 123; print(x);
|
|
x += 123.1; print(x);
|
|
x += four + 1; print(x);
|
|
x += y; print(x);
|
|
|
|
// Parenthesis don't affect the top level status.
|
|
|
|
(x = true); print(x);
|
|
(x = 123); print(x);
|
|
(x = 123.1); print(x);
|
|
(x = four + 1); print(x);
|
|
(x = y); print(x);
|
|
|
|
(x += true); print(x);
|
|
(x += 123); print(x);
|
|
(x += 123.1); print(x);
|
|
(x += four + 1); print(x);
|
|
(x += y); print(x);
|
|
|
|
// Comma expression doesn't affect top level status.
|
|
|
|
x = true, print('post: ' + x);
|
|
x = 123, print('post: ' + x);
|
|
x = 123.1, print('post: ' + x);
|
|
x = four + 1, print('post: ' + x);
|
|
x = y, print('post: ' + x);
|
|
|
|
x += true, print('post: ' + x);
|
|
x += 123, print('post: ' + x);
|
|
x += 123.1, print('post: ' + x);
|
|
x += four + 1, print('post: ' + x);
|
|
x += y, print('post: ' + x);
|
|
|
|
print('pre: ' + x), x = true, print('post: ' + x);
|
|
print('pre: ' + x), x = 123, print('post: ' + x);
|
|
print('pre: ' + x), x = 123.1, print('post: ' + x);
|
|
print('pre: ' + x), x = four + 1, print('post: ' + x);
|
|
print('pre: ' + x), x = y, print('post: ' + x);
|
|
|
|
print('pre: ' + x), x += true, print('post: ' + x);
|
|
print('pre: ' + x), x += 123, print('post: ' + x);
|
|
print('pre: ' + x), x += 123.1, print('post: ' + x);
|
|
print('pre: ' + x), x += four + 1, print('post: ' + x);
|
|
print('pre: ' + x), x += y, print('post: ' + x);
|
|
|
|
// Being inside a function call (or any other expression type)
|
|
// removes top level status.
|
|
|
|
print(x = true); print(x);
|
|
print(x = 123); print(x);
|
|
print(x = 123.1); print(x);
|
|
print(x = four + 1); print(x);
|
|
print(x = y); print(x);
|
|
|
|
print(x += true); print(x);
|
|
print(x += 123); print(x);
|
|
print(x += 123.1); print(x);
|
|
print(x += four + 1); print(x);
|
|
print(x += y); print(x);
|
|
|
|
// Intermediate values must be independent of 'x'.
|
|
|
|
print( ((x = 10) + (x = 20)) + ((x = 30) + (x = 40)) );
|
|
print( ((x = y1) + (x = y2)) + ((x = y3) + (x = y4)) );
|
|
|
|
x = 100;
|
|
print( ((x += 10) + (x += 20)) + ((x += 30) + (x += 40)) );
|
|
print( ((x += y1) + (x += y2)) + ((x += y3) + (x += y4)) );
|
|
|
|
// Both LHS and RHS are mutated so an actual temp is mandatory.
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( ((x = y1) + (x = y1 = y2)) + ((x = y1 = y2 = y3) + (x = y1 = y2 = y3 = y4)) );
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( ((x += y1) + (x += y1 += y2)) + ((x += y1 += y2 += y3) + (x += y1 += y2 += y3 += y4)) );
|
|
|
|
// Unresolved addition as RHS. Must be computed exactly once
|
|
// so that side effects are not repeated.
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print(x = 1 + 2); print(x);
|
|
|
|
var obj1 = {valueOf: function() { print('arg1'); return 123; }};
|
|
var obj2 = {valueOf: function() { print('arg2'); return 234; }};
|
|
print(x = obj1 + obj2);
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
x = y1 + y2; print(x);
|
|
|
|
y1 = 10; y2 = 20; y3 = 30; y4 = 40;
|
|
print( (x = y1 + y2) + (x = y3 + y4) );
|
|
}
|
|
|
|
try {
|
|
print('fast path');
|
|
fastPathAssignTest();
|
|
} catch (e) {
|
|
print(e.stack || e);
|
|
}
|
|
|
|
/*===
|
|
misc assign test
|
|
50
|
|
70
|
|
120
|
|
50
|
|
70
|
|
120
|
|
50
|
|
70
|
|
120
|
|
50
|
|
70
|
|
120
|
|
50
|
|
70
|
|
120
|
|
50
|
|
70
|
|
120
|
|
17.1
|
|
30
|
|
123
|
|
123.1
|
|
30
|
|
123
|
|
123.1
|
|
30 123 123.1
|
|
===*/
|
|
|
|
function miscAssignTest() {
|
|
var x = 10;
|
|
var y = 20;
|
|
var z = 30;
|
|
var w;
|
|
var obj = { foo: 0 };
|
|
|
|
// On the top level these should not use a temporary, and e.g.
|
|
// x = y + z should compile to a single ADD.
|
|
x = y + z; print(x);
|
|
x += y; print(x);
|
|
x += y + z; print(x);
|
|
|
|
// Outside of top level a temporary must be used.
|
|
w = x = y + z; print(x);
|
|
w = x += y; print(x);
|
|
w = x += y + z; print(x);
|
|
|
|
// Same tests for a non-reg-bound variable.
|
|
glob = y + z; print(glob);
|
|
glob += y; print(glob);
|
|
glob += y + z; print(glob);
|
|
w = glob = y + z; print(glob);
|
|
w = glob += y; print(glob);
|
|
w = glob += y + z; print(glob);
|
|
|
|
// And for a property LHS.
|
|
obj.foo = y + z; print(obj.foo);
|
|
obj.foo += y; print(obj.foo);
|
|
obj.foo += y + z; print(obj.foo);
|
|
w = obj.foo = y + z; print(obj.foo);
|
|
w = obj.foo += y; print(obj.foo);
|
|
w = obj.foo += y + z; print(obj.foo);
|
|
|
|
// Bytecode tests (inspect manually)
|
|
x = 10;
|
|
x += 3;
|
|
x += 3.1;
|
|
x += true;
|
|
print(x);
|
|
|
|
x = 10; y = 20;
|
|
glob = +(x + y); print(glob);
|
|
glob = 123; print(glob);
|
|
glob = 123.1; print(glob);
|
|
w = glob = +(x + y); print(glob);
|
|
w = glob = 123; print(glob);
|
|
w = glob = 123.1; print(glob);
|
|
print(glob = +(x + y), glob = 123, glob = 123.1);
|
|
}
|
|
|
|
try {
|
|
print('misc assign test');
|
|
miscAssignTest();
|
|
} catch (e) {
|
|
print(e.stack || e);
|
|
}
|
|
|