Browse Source

Testcases for assignment handling

pull/380/head
Sami Vaarala 9 years ago
parent
commit
09abe09569
  1. 532
      tests/ecmascript/test-dev-assign-expr.js
  2. 81
      tests/ecmascript/test-dev-assign-ldint.js

532
tests/ecmascript/test-dev-assign-expr.js

@ -0,0 +1,532 @@
/*
* 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);
}

81
tests/ecmascript/test-dev-assign-ldint.js

@ -0,0 +1,81 @@
/*
* "x = 1234" compiles to an LDINT if RHS is LDINT compatible.
* Check boundary conditions.
*/
/*===
-131073
-131072
-131071
131070
131071
131072
0 -Infinity
0 Infinity
0.5
-131073
-131072
-131071
131070
131071
131072
0 -Infinity
0 Infinity
0.5
-131073
-131072
-131071
131070
131071
131072
0 -Infinity
0 Infinity
0.5
===*/
var glob;
function test() {
var x;
var obj = {};
/* DUK_BC_LDINT_BIAS is 1 << 17 = 131072, so that LDINT range is
* [-131072, 131071].
*/
x = -131073; print(x);
x = -131072; print(x);
x = -131071; print(x);
x = 131070; print(x);
x = 131071; print(x);
x = 131072; print(x);
x = -0; print(x, 1/x);
x = +0; print(x, 1/x);
x = 0.5; print(x);
obj.foo = -131073; print(obj.foo);
obj.foo = -131072; print(obj.foo);
obj.foo = -131071; print(obj.foo);
obj.foo = 131070; print(obj.foo);
obj.foo = 131071; print(obj.foo);
obj.foo = 131072; print(obj.foo);
obj.foo = -0; print(obj.foo, 1/obj.foo);
obj.foo = +0; print(obj.foo, 1/obj.foo);
obj.foo = 0.5; print(obj.foo);
glob = -131073; print(glob);
glob = -131072; print(glob);
glob = -131071; print(glob);
glob = 131070; print(glob);
glob = 131071; print(glob);
glob = 131072; print(glob);
glob = -0; print(glob, 1/glob);
glob = +0; print(glob, 1/glob);
glob = 0.5; print(glob);
}
try {
test();
} catch (e) {
print(e.stack || e);
}
Loading…
Cancel
Save