Bug 880204 - Asm.js: support constant global variables and make their loads hoistable. r=luke

This commit is contained in:
Douglas Crosher 2013-09-13 17:35:38 +10:00
parent 291c5e6623
commit 486538c27a
9 changed files with 243 additions and 33 deletions

View File

@ -7,10 +7,10 @@ const ASM_TYPE_FAIL_STRING = "asm.js type error:";
const ASM_DIRECTIVE_FAIL_STRING = "\"use asm\" is only meaningful in the Directive Prologue of a function body";
const USE_ASM = "'use asm';";
const HEAP_IMPORTS = "var i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);"+
"var i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);"+
"var i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);"+
"var f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";
const HEAP_IMPORTS = "const i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);"+
"const i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);"+
"const i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);"+
"const f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";
const BUF_64KB = new ArrayBuffer(64 * 1024);
function asmCompile()

View File

@ -48,8 +48,11 @@ assertEq(f(), 2);
assertEq(counter, 3);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add1=imp.add1; function g(i) { i=i|0; return add1(i|0)|0 } return g'), null, imp)(9), 10);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'const add1=imp.add1; function g(i) { i=i|0; return add1(i|0)|0 } return g'), null, imp)(9), 10);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add3=imp.add3; function g() { var i=1,j=3,k=9; return add3(i|0,j|0,k|0)|0 } return g'), null, imp)(), 13);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'const add3=imp.add3; function g() { var i=1,j=3,k=9; return add3(i|0,j|0,k|0)|0 } return g'), null, imp)(), 13);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add3=imp.add3; function g() { var i=1.4,j=2.3,k=32.1; return +add3(i,j,k) } return g'), null, imp)(), 1.4+2.3+32.1);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'const add3=imp.add3; function g() { var i=1.4,j=2.3,k=32.1; return +add3(i,j,k) } return g'), null, imp)(), 1.4+2.3+32.1);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add3=imp.add3; function f(i,j,k) { i=i|0;j=+j;k=k|0; return add3(i|0,j,k|0)|0 } return f'), null, imp)(1, 2.5, 3), 6);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var addN=imp.addN; function f() { return +addN(1,2,3,4.1,5,6.1,7,8.1,9.1,10,11.1,12,13,14.1,15.1,16.1,17.1,18.1) } return f'), null, imp)(), 1+2+3+4.1+5+6.1+7+8.1+9.1+10+11.1+12+13+14.1+15.1+16.1+17.1+18.1);

View File

@ -27,18 +27,42 @@ assertAsmTypeFail(USE_ASM + "function f(i) {i=i|0} function g(i) { i=i|0; return
assertAsmTypeFail(USE_ASM + "function f(i) {i=i|0} function g(i) { i=i|0; return tbl[i&1](3.0)|0 } var tbl=[f,f]; return g");
assertAsmTypeFail(USE_ASM + "function f(d) {d=+d} function g(i) { i=i|0; return tbl[i&1](3)|0 } var tbl=[f,f]; return g");
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g(i) { i=i|0; return tbl[i&1]()|0 } var tbl=[f,f]; return g"))(0), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g(i) { i=i|0; return tbl[i&1]()|0 } const tbl=[f,f]; return g"))(0), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl[i&1]()|0 } var tbl=[f,g]; return h"))(1), 13);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl[i&1]()|0 } const tbl=[f,g]; return h"))(1), 13);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&1]()|0 } var tbl1=[f,g]; var tbl2=[g,f]; return h"))(1), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&1]()|0 } const tbl1=[f,g]; const tbl2=[g,f]; return h"))(1), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&3]()|0 } var tbl1=[f,g]; var tbl2=[g,g,g,f]; return h"))(3), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&3]()|0 } const tbl1=[f,g]; const tbl2=[g,g,g,f]; return h"))(3), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl1[i&1]()|0 } var tbl1=[f,g]; var tbl2=[g,g,g,f]; return h"))(1), 13);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl1[i&1]()|0 } const tbl1=[f,g]; const tbl2=[g,g,g,f]; return h"))(1), 13);
assertEq(asmLink(asmCompile(USE_ASM + "var i=0,j=0; function f() {return i|0} function g() {return j|0} function h(x) { x=x|0; i=5;j=10; return tbl2[x&3]()|0 } var tbl1=[f,g]; var tbl2=[g,g,g,f]; return h"))(3), 5);
assertEq(asmLink(asmCompile(USE_ASM + "var i=0,j=0; function f() {return i|0} function g() {return j|0} function h(x) { x=x|0; i=5;j=10; return tbl2[x&3]()|0 } const tbl1=[f,g]; const tbl2=[g,g,g,f]; return h"))(3), 5);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "var ffi=imp.ffi; function f() {return ffi()|0} function g() {return 13} function h(x) { x=x|0; return tbl2[x&3]()|0 } var tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 20);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "var ffi=imp.ffi; var i=0; function f() {return ((ffi()|0)+i)|0} function g() {return 13} function h(x) { x=x|0; i=2; return tbl2[x&3]()|0 } var tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 22);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "const ffi=imp.ffi; function f() {return ffi()|0} function g() {return 13} function h(x) { x=x|0; return tbl2[x&3]()|0 } const tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 20);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "var ffi=imp.ffi; var i=0; function f() {return ((ffi()|0)+i)|0} function g() {return 13} function h(x) { x=x|0; i=2; return tbl2[x&3]()|0 } var tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 22)
;assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "const ffi=imp.ffi; var i=0; function f() {return ((ffi()|0)+i)|0} function g() {return 13} function h(x) { x=x|0; i=2; return tbl2[x&3]()|0 } const tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 22);
assertEq(asmLink(asmCompile(USE_ASM + "function f(i) {i=i|0; return +((i+1)|0)} function g(d) { d=+d; return +(d+2.5) } function h(i,j) { i=i|0;j=j|0; return +tbl2[i&1](+tbl1[i&1](j)) } var tbl1=[f,f]; var tbl2=[g,g]; return h"))(0,10), 11+2.5);
assertEq(asmLink(asmCompile(USE_ASM + "function f(i) {i=i|0; return +((i+1)|0)} function g(d) { d=+d; return +(d+2.5) } function h(i,j) { i=i|0;j=j|0; return +tbl2[i&1](+tbl1[i&1](j)) } const tbl1=[f,f]; const tbl2=[g,g]; return h"))(0,10), 11+2.5);
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0]()|0 } var tbl=[f]; return g");
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() { return tbl[0&0]()|0 } var tbl=[f]; return g"))(), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() { return tbl[0&0]()|0 } const tbl=[f]; return g"))(), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f1() {return 42} function f2() {return 13} function g() { return tbl[1&1]()|0 } var tbl=[f1,f2]; return g"))(), 13);
assertEq(asmLink(asmCompile(USE_ASM + "function f1() {return 42} function f2() {return 13} function g() { return tbl[1&1]()|0 } const tbl=[f1,f2]; return g"))(), 13);
// Test some literal constant paths.
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&4294967295]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "const i=4294967295; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&-1]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "const i=-1; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&0x80000000]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "const i=0x80000000; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&-2147483648]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "const i=-2147483648; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
assertAsmTypeFail(USE_ASM + "const i=0; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
// Limited by the inability to test really large tables.
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&0x7fffffff]()|0 } var tbl=[f]; return g");
var f = asmLink(asmCompile(USE_ASM + "function f1(d) {d=+d; return +(d/2.0)} function f2(d) {d=+d; return +(d+10.0)} function g(i,j) { i=i|0;j=+j; return +tbl[i&1](+tbl[(i+1)&1](j)) } var tbl=[f1,f2]; return g"));
assertEq(f(0,10.2), (10.2+10)/2);

View File

@ -1,15 +1,29 @@
load(libdir + "asm.js");
assertAsmTypeFail(USE_ASM + "var i; function f(){} return f");
assertAsmTypeFail(USE_ASM + "const i; function f(){} return f");
assertEq(asmLink(asmCompile(USE_ASM + "var i=0; function f(){} return f"))(), undefined);
assertEq(asmLink(asmCompile(USE_ASM + "const i=0; function f(){} return f"))(), undefined);
assertEq(asmLink(asmCompile(USE_ASM + "var i=42; function f(){ return i|0 } return f"))(), 42);
assertEq(asmLink(asmCompile(USE_ASM + "const i=42; function f(){ return i|0 } return f"))(), 42);
assertEq(asmLink(asmCompile(USE_ASM + "var i=4.2; function f(){ return +i } return f"))(), 4.2);
assertEq(asmLink(asmCompile(USE_ASM + "const i=4.2; function f(){ return +i } return f"))(), 4.2);
assertAsmTypeFail(USE_ASM + "var i=42; function f(){ return +(i+.1) } return f");
assertAsmTypeFail(USE_ASM + "const i=42; function f(){ return +(i+.1) } return f");
assertAsmTypeFail(USE_ASM + "var i=1.2; function f(){ return i|0 } return f");
assertAsmTypeFail(USE_ASM + "const i=1.2; function f(){ return i|0 } return f");
assertAsmTypeFail(USE_ASM + "var i=0; function f(e){ e=+e; i=e } return f");
assertAsmTypeFail(USE_ASM + "const i=0; function f(e){ e=+e; i=e } return f");
assertAsmTypeFail(USE_ASM + "var d=0.1; function f(i){ i=i|0; d=i } return f");
assertAsmTypeFail(USE_ASM + "const d=0.1; function f(i){ i=i|0; d=i } return f");
assertEq(asmLink(asmCompile(USE_ASM + "var i=13; function f(j) { j=j|0; i=j; return i|0 } return f"))(42), 42);
assertAsmTypeFail(USE_ASM + "const i=13; function f(j) { j=j|0; i=j; return i|0 } return f");
assertAsmTypeFail(USE_ASM + "const c=0,i=13; function f(j) { j=j|0; i=j; return i|0 } return f");
assertEq(asmLink(asmCompile(USE_ASM + "var d=.1; function f(e) { e=+e; d=e; return +e } return f"))(42.1), 42.1);
assertAsmTypeFail(USE_ASM + "const d=.1; function f(e) { e=+e; d=e; return +e } return f");
assertAsmTypeFail(USE_ASM + "const c=0, d=.1; function f(e) { e=+e; d=e; return +e } return f");
assertEq(asmLink(asmCompile(USE_ASM + "var i=13; function f(i, j) { i=i|0; j=j|0; i=j; return i|0 } return f"))(42,43), 43);
assertEq(asmLink(asmCompile(USE_ASM + "var i=13; function f(j) { j=j|0; var i=0; i=j; return i|0 } return f"))(42), 42);
var f = asmLink(asmCompile(USE_ASM + "var i=13; function f(j) { j=j|0; if ((j|0) != -1) { i=j } else { return i|0 } return 0 } return f"));
assertEq(f(-1), 13);
@ -17,19 +31,27 @@ assertEq(f(42), 0);
assertEq(f(-1), 42);
assertAsmTypeFail('global', USE_ASM + "var i=global; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "const i=global; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "var i=global|0; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "const i=global|0; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "var j=0;var i=j.i|0; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "var i=global.i|0; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "const i=global.i|0; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + "var i=global.i|0; function f() { return i|0 } return f");
assertAsmTypeFail('global', USE_ASM + 'var i=global.Infinity; function f() { i = 0.0 } return f');
assertAsmTypeFail('global', USE_ASM + 'const i=global.Infinity; function f() { i = 0.0 } return f');
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), undefined);
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), undefined);
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), null);
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), null);
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), 3);
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {});
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {Infinity:NaN});
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {Infinity:-Infinity});
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {Infinity:Infinity})(), Infinity);
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), {Infinity:Infinity})(), Infinity);
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), this)(), Infinity);
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), this)(), Infinity);
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), undefined);
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), null);
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), 3);
@ -37,10 +59,14 @@ assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f()
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), {Infinity:Infinity});
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), {Infinity:-Infinity});
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), {NaN:NaN})(), NaN);
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.NaN; function f() { return +i } return f'), {NaN:NaN})(), NaN);
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), this)(), NaN);
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.NaN; function f() { return +i } return f'), this)(), NaN);
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'var t = new glob.Int32Array(buf); function f() {} return f'), {get Int32Array(){return Int32Array}}, null, new ArrayBuffer(4096))
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'const t = new glob.Int32Array(buf); function f() {} return f'), {get Int32Array(){return Int32Array}}, null, new ArrayBuffer(4096))
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'var t = new glob.Int32Array(buf); function f() {} return f'), new Proxy({}, {get:function() {return Int32Array}}), null, new ArrayBuffer(4096))
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'const t = new glob.Int32Array(buf); function f() {} return f'), new Proxy({}, {get:function() {return Int32Array}}), null, new ArrayBuffer(4096))
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var t = glob.Math.sin; function f() {} return f'), {get Math(){return Math}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var t = glob.Math.sin; function f() {} return f'), new Proxy({}, {get:function(){return Math}}));
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var t = glob.Math.sin; function f() {} return f'), {Math:{get sin(){return Math.sin}}});
@ -61,9 +87,13 @@ assertAsmLinkAlwaysFail(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; fu
assertAsmLinkAlwaysFail(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f"), this, null);
assertAsmLinkFail(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f"), this, 42);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f")(null, {i:42})), 42);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=imp.i|0; function f() { return i|0 } return f")(null, {i:42})), 42);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f")(null, {i:1.4})), 1);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=imp.i|0; function f() { return i|0 } return f")(null, {i:1.4})), 1);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(null, {i:42})), 42);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(null, {i:42})), 42);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f() { var i=42; while (1) { break; } g = i; return g|0 } return f"))(), 42);
var f1 = asmCompile('global', 'foreign', 'heap', USE_ASM + 'var i32 = new global.Int32Array(heap); function g() { return i32[4]|0 } return g');

View File

@ -453,3 +453,81 @@ assertEq(new Int32Array(buf)[0], 1);
// Bug 882012
assertEq(asmLink(asmCompile('stdlib', 'foreign', 'heap', USE_ASM + "var id=foreign.id;var doubles=new stdlib.Float64Array(heap);function g(){doubles[0]=+id(2.0);return +doubles[0];}return g"), this, {id: function(x){return x;}}, BUF_64KB)(), 2.0);
// Some literal constant paths.
var buf = new ArrayBuffer(8192);
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>4294967295]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>-1]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>0x80000000]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>-2147483648]|0; } return f');
new Uint32Array(buf)[0] = 0xAA;
new Uint32Array(buf)[0x5A>>2] = 0xA5;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&4294967295)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&-1)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&0x80000000)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&-2147483648)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(4294967295&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u32[(i&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(-1&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u32[(i&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x80000000&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u32[(i&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(-2147483648&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u32[(-2147483648&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[4294967295>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u32[i>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[-1>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u32[i>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0x80000000>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u32[i>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[-2147483648>>2]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u32[-2147483648>>2]|0; } return f'), this, null, buf)(),0);
var buf = new ArrayBuffer(8192);
new Uint8Array(buf)[0] = 0xAA;
new Uint8Array(buf)[0x5A] = 0xA5;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&4294967295]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&-1]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&0x80000000]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&-2147483648]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[4294967295&0x5A]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-1&0x5A]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xA5);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x80000000&0x5A]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-2147483648&0x5A]|0; } return f'), this, null, buf)(),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xAA);
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[4294967295]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[i]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-1]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[i]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x80000000]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[i]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-2147483648]|0; } return f');
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i]|0; } return f');
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[4294967295>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-1>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x80000000>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-2147483648>>0]|0; } return f'), this, null, buf)(),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);

View File

@ -41,6 +41,10 @@ assertEq(asmLink(asmCompile(USE_ASM + 'function f(i) { i=i|0; return (i+-2147483
assertEq(asmLink(asmCompile(USE_ASM + 'function f(i) { i=i|0; return (i+4294967295)|0 } return f'))(0), 4294967295|0);
assertAsmTypeFail(USE_ASM + 'var i=-2147483649; function f() { return i|0 } return f');
assertAsmTypeFail(USE_ASM + 'const i=-2147483649; function f() { return i|0 } return f');
assertAsmTypeFail(USE_ASM + 'var i=4294967296; function f() { return i|0 } return f');
assertAsmTypeFail(USE_ASM + 'const i=4294967296; function f() { return i|0 } return f');
assertEq(asmLink(asmCompile(USE_ASM + 'var i=-2147483648; function f() { return i|0 } return f'))(), -2147483648);
assertEq(asmLink(asmCompile(USE_ASM + 'const i=-2147483648; function f() { return i|0 } return f'))(), -2147483648);
assertEq(asmLink(asmCompile(USE_ASM + 'var i=4294967295; function f() { return i|0 } return f'))(), 4294967295|0);
assertEq(asmLink(asmCompile(USE_ASM + 'const i=4294967295; function f() { return i|0 } return f'))(), 4294967295|0);

View File

@ -9,6 +9,7 @@ function testUnary(f, g) {
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:Math.sqrt}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:null}});
testUnary(asmLink(asmCompile('glob', USE_ASM + 'var sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:Math.sin}}), Math.sin);
testUnary(asmLink(asmCompile('glob', USE_ASM + 'const sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:Math.sin}}), Math.sin);
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var co=glob.Math.cos; function f(d) { d=+d; return +co(d) } return f'), {Math:{cos:Math.sqrt}});
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var co=glob.Math.cos; function f(d) { d=+d; return +co(d) } return f'), {Math:{cos:null}});

View File

@ -146,7 +146,7 @@ CallArgList(ParseNode *pn)
static inline ParseNode *
VarListHead(ParseNode *pn)
{
JS_ASSERT(pn->isKind(PNK_VAR));
JS_ASSERT(pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST));
return ListHead(pn);
}
@ -370,9 +370,10 @@ PeekToken(AsmJSParser &parser)
}
static bool
ParseVarStatement(AsmJSParser &parser, ParseNode **var)
ParseVarOrConstStatement(AsmJSParser &parser, ParseNode **var)
{
if (PeekToken(parser) != TOK_VAR) {
TokenKind tk = PeekToken(parser);
if (tk != TOK_VAR && tk != TOK_CONST) {
*var = NULL;
return true;
}
@ -381,7 +382,7 @@ ParseVarStatement(AsmJSParser &parser, ParseNode **var)
if (!*var)
return false;
JS_ASSERT((*var)->isKind(PNK_VAR));
JS_ASSERT((*var)->isKind(PNK_VAR) || (*var)->isKind(PNK_CONST));
return true;
}
@ -823,7 +824,7 @@ ExtractNumericLiteral(ParseNode *pn)
}
static inline bool
IsLiteralUint32(ParseNode *pn, uint32_t *u32)
IsLiteralInt(ParseNode *pn, uint32_t *u32)
{
if (!IsNumericLiteral(pn))
return false;
@ -832,9 +833,9 @@ IsLiteralUint32(ParseNode *pn, uint32_t *u32)
switch (literal.which()) {
case NumLit::Fixnum:
case NumLit::BigUnsigned:
case NumLit::NegativeInt:
*u32 = uint32_t(literal.toInt32());
return true;
case NumLit::NegativeInt:
case NumLit::Double:
case NumLit::OutOfRangeInt:
return false;
@ -1019,6 +1020,9 @@ class MOZ_STACK_CLASS ModuleCompiler
struct {
uint32_t index_;
VarType::Which type_;
bool isConst_;
bool isLitConst_;
Value litConstValue_;
} var;
uint32_t funcIndex_;
uint32_t funcPtrTableIndex_;
@ -1045,6 +1049,19 @@ class MOZ_STACK_CLASS ModuleCompiler
JS_ASSERT(which_ == Variable);
return u.var.index_;
}
bool varIsConstant() const {
JS_ASSERT(which_ == Variable);
return u.var.isConst_;
}
bool varIsLitConstant() const {
JS_ASSERT(which_ == Variable);
return u.var.isLitConst_;
}
const Value &litConstValue() const {
JS_ASSERT(which_ == Variable);
JS_ASSERT(u.var.isLitConst_);
return u.var.litConstValue_;
}
uint32_t funcIndex() const {
JS_ASSERT(which_ == Function);
return u.funcIndex_;
@ -1361,7 +1378,8 @@ class MOZ_STACK_CLASS ModuleCompiler
void initImportArgumentName(PropertyName *n) { module_->initImportArgumentName(n); }
void initBufferArgumentName(PropertyName *n) { module_->initBufferArgumentName(n); }
bool addGlobalVarInitConstant(PropertyName *varName, VarType type, const Value &v) {
bool addGlobalVarInitConstant(PropertyName *varName, VarType type, const Value &v,
bool isConst) {
uint32_t index;
if (!module_->addGlobalVarInitConstant(v, &index))
return false;
@ -1370,9 +1388,14 @@ class MOZ_STACK_CLASS ModuleCompiler
return false;
global->u.var.index_ = index;
global->u.var.type_ = type.which();
global->u.var.isConst_ = isConst;
global->u.var.isLitConst_ = isConst;
if (isConst)
global->u.var.litConstValue_ = v;
return globals_.putNew(varName, global);
}
bool addGlobalVarImport(PropertyName *varName, PropertyName *fieldName, AsmJSCoercion coercion) {
bool addGlobalVarImport(PropertyName *varName, PropertyName *fieldName, AsmJSCoercion coercion,
bool isConst) {
uint32_t index;
if (!module_->addGlobalVarImport(fieldName, coercion, &index))
return false;
@ -1381,6 +1404,8 @@ class MOZ_STACK_CLASS ModuleCompiler
return false;
global->u.var.index_ = index;
global->u.var.type_ = VarType(coercion).which();
global->u.var.isConst_ = isConst;
global->u.var.isLitConst_ = false;
return globals_.putNew(varName, global);
}
bool addFunction(PropertyName *name, MoveRef<Signature> sig, Func **func) {
@ -1990,9 +2015,16 @@ class FunctionCompiler
{
if (!curBlock_)
return NULL;
if (global.varIsLitConstant()) {
JS_ASSERT(global.litConstValue().isNumber());
MConstant *constant = MConstant::New(global.litConstValue());
curBlock_->add(constant);
return constant;
}
MIRType type = global.varType().toMIRType();
unsigned globalDataOffset = module().globalVarIndexToGlobalDataOffset(global.varIndex());
MAsmJSLoadGlobalVar *load = MAsmJSLoadGlobalVar::New(type, globalDataOffset);
MAsmJSLoadGlobalVar *load = MAsmJSLoadGlobalVar::New(type, globalDataOffset,
global.varIsConstant());
curBlock_->add(load);
return load;
}
@ -2692,7 +2724,8 @@ CheckPrecedingStatements(ModuleCompiler &m, ParseNode *stmtList)
}
static bool
CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode)
CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
bool isConst)
{
NumLit literal = ExtractNumericLiteral(initNode);
VarType type;
@ -2708,7 +2741,7 @@ CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseN
case NumLit::OutOfRangeInt:
return m.fail(initNode, "global initializer is out of representable integer range");
}
return m.addGlobalVarInitConstant(varName, type, literal.value());
return m.addGlobalVarInitConstant(varName, type, literal.value(), isConst);
}
static bool
@ -2744,7 +2777,8 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c
}
static bool
CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode)
CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
bool isConst)
{
AsmJSCoercion coercion;
ParseNode *coercedExpr;
@ -2763,7 +2797,7 @@ CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNod
if (!IsUseOfName(base, importName))
return m.failName(coercedExpr, "base of import expression must be '%s'", importName);
return m.addGlobalVarImport(varName, field, coercion);
return m.addGlobalVarImport(varName, field, coercion, isConst);
}
static bool
@ -2850,7 +2884,7 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo
}
static bool
CheckModuleGlobal(ModuleCompiler &m, ParseNode *var)
CheckModuleGlobal(ModuleCompiler &m, ParseNode *var, bool isConst)
{
if (!IsDefinition(var))
return m.fail(var, "import variable names must be unique");
@ -2863,10 +2897,10 @@ CheckModuleGlobal(ModuleCompiler &m, ParseNode *var)
return m.fail(var, "module import needs initializer");
if (IsNumericLiteral(initNode))
return CheckGlobalVariableInitConstant(m, var->name(), initNode);
return CheckGlobalVariableInitConstant(m, var->name(), initNode, isConst);
if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS))
return CheckGlobalVariableInitImport(m, var->name(), initNode);
return CheckGlobalVariableInitImport(m, var->name(), initNode, isConst);
if (initNode->isKind(PNK_NEW))
return CheckNewArrayView(m, var->name(), initNode);
@ -2882,12 +2916,12 @@ CheckModuleGlobals(ModuleCompiler &m)
{
while (true) {
ParseNode *varStmt;
if (!ParseVarStatement(m.parser(), &varStmt))
if (!ParseVarOrConstStatement(m.parser(), &varStmt))
return false;
if (!varStmt)
break;
for (ParseNode *var = VarListHead(varStmt); var; var = NextNode(var)) {
if (!CheckModuleGlobal(m, var))
if (!CheckModuleGlobal(m, var, varStmt->isKind(PNK_CONST)))
return false;
}
}
@ -3106,6 +3140,30 @@ CheckVarRef(FunctionCompiler &f, ParseNode *varRef, MDefinition **def, Type *typ
return f.failName(varRef, "'%s' not found in local or asm.js module scope", name);
}
static inline bool
IsLiteralOrConstInt(FunctionCompiler &f, ParseNode *pn, uint32_t *u32)
{
if (IsLiteralInt(pn, u32))
return true;
if (pn->getKind() != PNK_NAME)
return false;
PropertyName *name = pn->name();
const ModuleCompiler::Global *global = f.lookupGlobal(name);
if (!global || global->which() != ModuleCompiler::Global::Variable ||
!global->varIsLitConstant()) {
return false;
}
const Value &v = global->litConstValue();
if (!v.isInt32())
return false;
*u32 = (uint32_t) v.toInt32();
return true;
}
static bool
FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
NeedsBoundsCheck *needsBoundsCheck)
@ -3114,7 +3172,7 @@ FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
ParseNode *maskNode = BinaryRight(*indexExpr);
uint32_t mask2;
if (IsLiteralUint32(maskNode, &mask2)) {
if (IsLiteralOrConstInt(f, maskNode, &mask2)) {
// Flag the access to skip the bounds check if the mask ensures that an 'out of
// bounds' access can not occur based on the current heap length constraint.
if (mask2 == 0 ||
@ -3147,7 +3205,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
*viewType = global->viewType();
uint32_t pointer;
if (IsLiteralUint32(indexExpr, &pointer)) {
if (IsLiteralOrConstInt(f, indexExpr, &pointer)) {
if (pointer > (uint32_t(INT32_MAX) >> TypedArrayShift(*viewType)))
return f.fail(indexExpr, "constant index out of range");
pointer <<= TypedArrayShift(*viewType);
@ -3171,7 +3229,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
ParseNode *pointerNode = BinaryLeft(indexExpr);
uint32_t shift;
if (!IsLiteralUint32(shiftNode, &shift))
if (!IsLiteralInt(shiftNode, &shift))
return f.failf(shiftNode, "shift amount must be constant");
unsigned requiredShift = TypedArrayShift(*viewType);
@ -3184,7 +3242,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
// Fold a 'literal constant right shifted' now, and skip the bounds check if
// currently possible. This handles the optimization of many of these uses without
// the need for range analysis, and saves the generation of a MBitAnd op.
if (IsLiteralUint32(pointerNode, &pointer) && pointer <= uint32_t(INT32_MAX)) {
if (IsLiteralOrConstInt(f, pointerNode, &pointer) && pointer <= uint32_t(INT32_MAX)) {
// Cases: b[c>>n], and b[(c&m)>>n]
pointer &= mask;
if (pointer < f.m().minHeapLength())
@ -3297,6 +3355,8 @@ CheckAssignName(FunctionCompiler &f, ParseNode *lhs, ParseNode *rhs, MDefinition
} else if (const ModuleCompiler::Global *global = f.lookupGlobal(name)) {
if (global->which() != ModuleCompiler::Global::Variable)
return f.failName(lhs, "'%s' is not a mutable variable", name);
if (global->varIsConstant())
return f.failName(lhs, "'%s' is a constant variable and not mutable", name);
if (!(rhsType <= global->varType())) {
return f.failf(lhs, "%s is not a subtype of %s",
rhsType.toChars(), global->varType().toType().toChars());
@ -3560,7 +3620,7 @@ CheckFuncPtrCall(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDef
ParseNode *maskNode = BinaryRight(indexExpr);
uint32_t mask;
if (!IsLiteralUint32(maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
if (!IsLiteralInt(maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
return f.fail(maskNode, "function-pointer table index mask value must be a power of two");
MDefinition *indexDef;
@ -5187,7 +5247,7 @@ CheckFuncPtrTables(ModuleCompiler &m)
{
while (true) {
ParseNode *varStmt;
if (!ParseVarStatement(m.parser(), &varStmt))
if (!ParseVarOrConstStatement(m.parser(), &varStmt))
return false;
if (!varStmt)
break;

View File

@ -8434,23 +8434,33 @@ class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
class MAsmJSLoadGlobalVar : public MNullaryInstruction
{
MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset)
: globalDataOffset_(globalDataOffset)
MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant)
: globalDataOffset_(globalDataOffset), isConstant_(isConstant)
{
JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double);
setResultType(type);
if (isConstant)
setMovable();
}
unsigned globalDataOffset_;
bool isConstant_;
public:
INSTRUCTION_HEADER(AsmJSLoadGlobalVar);
static MAsmJSLoadGlobalVar *New(MIRType type, unsigned globalDataOffset) {
return new MAsmJSLoadGlobalVar(type, globalDataOffset);
static MAsmJSLoadGlobalVar *New(MIRType type, unsigned globalDataOffset, bool isConstant) {
return new MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant);
}
unsigned globalDataOffset() const { return globalDataOffset_; }
AliasSet getAliasSet() const {
if (isConstant_)
return AliasSet::None();
else
return AliasSet::Store(AliasSet::Any);
}
};
class MAsmJSStoreGlobalVar : public MUnaryInstruction