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

/*
* 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);
}