Bug 1014292 - OdinMonkey: restrict ArrayBuffer heap length rules to something regular and not ARM-specific (r=dougc)

This commit is contained in:
Luke Wagner 2014-05-28 16:17:34 -05:00
parent c81d90b9e0
commit 81219bd5c1
2 changed files with 57 additions and 162 deletions

View File

@ -544,99 +544,34 @@ assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'var i=
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'var i=0; function f() { var x = 0, y = 0; u8[0] = 1; u8[1] = 2; x = 0|u8[i]; y = 0|u8[i]; return (x+y)|0;} return f'), this, null, buf)(),2);
// Heap length constraints
var buf = new ArrayBuffer(0x0fff);
assertAsmLinkAlwaysFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
var buf = new ArrayBuffer(0x1000);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
var buf = new ArrayBuffer(0x1010);
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
var buf = new ArrayBuffer(0x2000);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
var buf = new ArrayBuffer(0xfe000);
new Uint8Array(buf)[0xfdfff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfdfff),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfe000),0);
var buf = new ArrayBuffer(0xfe010);
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
var buf = new ArrayBuffer(0xff000);
new Uint8Array(buf)[0xfefff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfefff),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff000),0);
var buf = new ArrayBuffer(0xff800);
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
var m = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f');
assertAsmLinkAlwaysFail(m, this, null, new ArrayBuffer(0x0fff));
assertEq(asmLink(m, this, null, new ArrayBuffer(0x1000))(0),0);
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x1010));
assertEq(asmLink(m, this, null, new ArrayBuffer(0x2000))(0),0);
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe000));
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe010));
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe000));
assertAsmLinkFail(m, this, null, new ArrayBuffer(0xff800));
var buf = new ArrayBuffer(0x100000);
new Uint8Array(buf)[0xfffff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfffff),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x100000),0);
var buf = new ArrayBuffer(0x104000);
new Uint8Array(buf)[0x103fff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x103fff]|0; } return f'), this, null, buf)(),0xAA);
var buf = new ArrayBuffer(0x3f8000);
new Uint8Array(buf)[0x3f7fff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3f7fff),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3f8000),0);
var buf = new ArrayBuffer(0x3fc000); // 4080K
new Uint8Array(buf)[0x3fbfff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbfff),0xAA);
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc000),0);
var buf = new ArrayBuffer(0x3fe000);
assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
var buf = new ArrayBuffer(0x410000);
new Uint8Array(buf)[0x40ffff] = 0xAA;
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x40ffff]|0; } return f'), this, null, buf)(),0xAA);
// The rest are getting too large for regular testing.
//var buf = new ArrayBuffer(0xfe8000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0xff0000); // 16302K
//new Uint8Array(buf)[0xfeffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfeffff),0xAA);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff0000),0);
//var buf = new ArrayBuffer(0xff8000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0x3fb0000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0x3fc0000); // 65280K
//new Uint8Array(buf)[0x3fbffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbffff),0xAA);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc0000),0);
//var buf = new ArrayBuffer(0x3fe0000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0xfe80000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0xff00000); // 255M
//new Uint8Array(buf)[0xfeffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfeffff),0xAA);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff00000),0);
//var buf = new ArrayBuffer(0xff80000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0x10400000);
//new Uint8Array(buf)[0x103fffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x103fffff]|0; } return f'), this, null, buf)(),0xAA);
//var buf = new ArrayBuffer(0x3fa00000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0x3fc00000); // 1020M
//new Uint8Array(buf)[0x3fbfffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbfffff),0xAA);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc00000),0);
//var buf = new ArrayBuffer(0x3fe00000);
//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
//var buf = new ArrayBuffer(0x40000000); // 1024M
//new Uint8Array(buf)[0x3fffffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fffffff),0xAA);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x40000000),0);
//var buf = new ArrayBuffer(0x4f000000); // 1264M - currently the largest possible heap length.
//new Uint8Array(buf)[0x4effffff] = 0xAA;
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x4effffff),0xAA);
//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x4f000000),0);
new Uint8Array(buf)[0x4242] = 0xAA;
var f = asmLink(m, this, null, buf);
assertEq(f(0),0);
assertEq(f(0x4242),0xAA);
assertEq(f(0x100000),0);
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x104000));
assertEq(asmLink(m, this, null, new ArrayBuffer(0x200000))(0),0);
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3f8000));
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3fe000));
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3fc000));
assertEq(asmLink(m, this, null, new ArrayBuffer(0x400000))(0),0);
assertAsmLinkFail(m, this, null, new ArrayBuffer(0x410000));
assertEq(asmLink(m, this, null, new ArrayBuffer(0x800000))(0),0);
var buf = new ArrayBuffer(0x1000000);
new Uint8Array(buf)[0x424242] = 0xAA;
var f = asmLink(m, this, null, buf);
assertEq(f(0),0);
assertEq(f(0x424242),0xAA);
assertEq(f(0x1000000),0);
assertEq(asmLink(m, this, null, new ArrayBuffer(0x2000000))(0),0);
assertEq(asmLink(m, this, null, new ArrayBuffer(0x3000000))(0),0);

View File

@ -7,8 +7,12 @@
#ifndef jit_AsmJS_h
#define jit_AsmJS_h
#include "mozilla/MathAlgorithms.h"
#include <stddef.h>
#include "jsutil.h"
#include "js/TypeDecls.h"
#include "vm/ObjectImpl.h"
@ -88,77 +92,33 @@ IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp)
#endif // JS_ION
// The Asm.js heap length is constrained by the x64 backend heap access scheme
// to be a multiple of the page size which is 4096 bytes, and also constrained
// by the limits of ARM backends 'cmp immediate' instruction which supports a
// complex range for the immediate argument.
//
// ARMv7 mode supports the following immediate constants, and the Thumb T2
// instruction encoding also supports the subset of immediate constants used.
// abcdefgh 00000000 00000000 00000000
// 00abcdef gh000000 00000000 00000000
// 0000abcd efgh0000 00000000 00000000
// 000000ab cdefgh00 00000000 00000000
// 00000000 abcdefgh 00000000 00000000
// 00000000 00abcdef gh000000 00000000
// 00000000 0000abcd efgh0000 00000000
// ...
//
// The 4096 page size constraint restricts the length to:
// xxxxxxxx xxxxxxxx xxxx0000 00000000
//
// Intersecting all the above constraints gives:
// Heap length 0x40000000 to 0xff000000 quanta 0x01000000
// Heap length 0x10000000 to 0x3fc00000 quanta 0x00400000
// Heap length 0x04000000 to 0x0ff00000 quanta 0x00100000
// Heap length 0x01000000 to 0x03fc0000 quanta 0x00040000
// Heap length 0x00400000 to 0x00ff0000 quanta 0x00010000
// Heap length 0x00100000 to 0x003fc000 quanta 0x00004000
// Heap length 0x00001000 to 0x000ff000 quanta 0x00001000
//
inline uint32_t
RoundUpToNextValidAsmJSHeapLength(uint32_t length)
{
if (length < 0x00001000u) // Minimum length is the pages size of 4096.
return 0x1000u;
if (length < 0x00100000u) // < 1M quanta 4K
return (length + 0x00000fff) & ~0x00000fff;
if (length < 0x00400000u) // < 4M quanta 16K
return (length + 0x00003fff) & ~0x00003fff;
if (length < 0x01000000u) // < 16M quanta 64K
return (length + 0x0000ffff) & ~0x0000ffff;
if (length < 0x04000000u) // < 64M quanta 256K
return (length + 0x0003ffff) & ~0x0003ffff;
if (length < 0x10000000u) // < 256M quanta 1M
return (length + 0x000fffff) & ~0x000fffff;
if (length < 0x40000000u) // < 1024M quanta 4M
return (length + 0x003fffff) & ~0x003fffff;
// < 4096M quanta 16M. Note zero is returned if over 0xff000000 but such
// lengths are not currently valid.
JS_ASSERT(length <= 0xff000000);
return (length + 0x00ffffff) & ~0x00ffffff;
}
// To succesfully link an asm.js module to an ArrayBuffer heap, the
// ArrayBuffer's byteLength must be:
// - greater or equal to 4096
// - either a power of 2 OR a multiple of 16MB
inline bool
IsValidAsmJSHeapLength(uint32_t length)
{
if (length < AsmJSAllocationGranularity)
if (length < 4096)
return false;
if (length <= 0x00100000u)
return (length & 0x00000fff) == 0;
if (length <= 0x00400000u)
return (length & 0x00003fff) == 0;
if (length <= 0x01000000u)
return (length & 0x0000ffff) == 0;
if (length <= 0x04000000u)
return (length & 0x0003ffff) == 0;
if (length <= 0x10000000u)
return (length & 0x000fffff) == 0;
if (length <= 0x40000000u)
return (length & 0x003fffff) == 0;
if (length <= 0xff000000u)
if (IsPowerOfTwo(length))
return true;
return (length & 0x00ffffff) == 0;
return false;
}
inline uint32_t
RoundUpToNextValidAsmJSHeapLength(uint32_t length)
{
if (length < 4096)
return 4096;
if (length < 16 * 1024 * 1024)
return mozilla::RoundUpPow2(length);
JS_ASSERT(length <= 0xff000000);
return (length + 0x00ffffff) & ~0x00ffffff;
}
} // namespace js