Bug 1253137 - Baldr: update memory section to match BinaryEncoding.md, part 1 (r=sunfish)

MozReview-Commit-ID: EKCvmgPnLmv
This commit is contained in:
Luke Wagner 2016-03-02 21:48:05 -06:00
parent b64899197c
commit 9f827324d4
5 changed files with 61 additions and 53 deletions

View File

@ -18,6 +18,8 @@
#include "asmjs/Wasm.h"
#include "mozilla/CheckedInt.h"
#include "jsprf.h"
#include "asmjs/WasmGenerator.h"
@ -30,6 +32,7 @@
using namespace js;
using namespace js::wasm;
using mozilla::CheckedInt;
using mozilla::IsNaN;
typedef Handle<WasmModuleObject*> HandleWasmModule;
@ -890,28 +893,29 @@ DecodeMemorySection(JSContext* cx, Decoder& d, ModuleGenerator& mg,
if (sectionStart == Decoder::NotStarted)
return true;
if (!d.readCStringIf(InitialLabel))
return Fail(cx, d, "expected memory section initial field");
uint32_t initialHeapSize;
if (!d.readVarU32(&initialHeapSize))
uint32_t initialSizePages;
if (!d.readVarU32(&initialSizePages))
return Fail(cx, d, "expected initial memory size");
if (initialHeapSize < PageSize || initialHeapSize % PageSize != 0)
return Fail(cx, d, "initial memory size not a multiple of 0x10000");
if (initialHeapSize > INT32_MAX)
CheckedInt<int32_t> initialSize = initialSizePages;
initialSize *= PageSize;
if (!initialSize.isValid())
return Fail(cx, d, "initial memory size too big");
if (!d.readCStringIf(EndLabel))
return Fail(cx, d, "expected end field of memory section");
uint32_t maxSizePages;
if (!d.readVarU32(&maxSizePages))
return Fail(cx, d, "expected initial memory size");
CheckedInt<int32_t> maxSize = maxSizePages;
maxSize *= PageSize;
if (!maxSize.isValid())
return Fail(cx, d, "initial memory size too big");
if (!d.finishSection(sectionStart))
return Fail(cx, d, "memory section byte size mismatch");
bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB;
heap.set(ArrayBufferObject::createForWasm(cx, initialHeapSize, signalsForOOB));
heap.set(ArrayBufferObject::createForWasm(cx, initialSize.value(), signalsForOOB));
if (!heap)
return false;

View File

@ -54,7 +54,6 @@ static const char ExportLabel[] = "export";
static const char FuncLabel[] = "func";
static const char DataLabel[] = "data";
static const char SegmentLabel[] = "segment";
static const char InitialLabel[] = "initial";
static const char EndLabel[] = "";
enum class Expr : uint16_t

View File

@ -562,14 +562,18 @@ typedef WasmAstVector<WasmAstSegment*> WasmAstSegmentVector;
class WasmAstMemory : public WasmAstNode
{
uint32_t initialSize_;
Maybe<uint32_t> maxSize_;
WasmAstSegmentVector segments_;
public:
explicit WasmAstMemory(uint32_t initialSize, WasmAstSegmentVector&& segments)
explicit WasmAstMemory(uint32_t initialSize, Maybe<uint32_t> maxSize,
WasmAstSegmentVector&& segments)
: initialSize_(initialSize),
maxSize_(maxSize),
segments_(Move(segments))
{}
uint32_t initialSize() const { return initialSize_; }
const Maybe<uint32_t>& maxSize() const { return maxSize_; }
const WasmAstSegmentVector& segments() const { return segments_; }
};
@ -2897,6 +2901,11 @@ ParseMemory(WasmParseContext& c)
if (!c.ts.match(WasmToken::Index, &initialSize, c.error))
return nullptr;
Maybe<uint32_t> maxSize;
WasmToken token;
if (c.ts.getIf(WasmToken::Index, &token))
maxSize.emplace(token.index());
WasmAstSegmentVector segments(c.lifo);
while (c.ts.getIf(WasmToken::OpenParen)) {
WasmAstSegment* segment = ParseSegment(c);
@ -2906,7 +2915,7 @@ ParseMemory(WasmParseContext& c)
return nullptr;
}
return new(c.lifo) WasmAstMemory(initialSize.index(), Move(segments));
return new(c.lifo) WasmAstMemory(initialSize.index(), maxSize, Move(segments));
}
static WasmAstImport*
@ -3814,13 +3823,11 @@ EncodeMemorySection(Encoder& e, WasmAstModule& module)
WasmAstMemory& memory = *module.maybeMemory();
if (!e.writeCString(InitialLabel))
return false;
if (!e.writeVarU32(memory.initialSize()))
return false;
if (!e.writeCString(EndLabel))
uint32_t maxSize = memory.maxSize() ? *memory.maxSize() : memory.initialSize();
if (!e.writeVarU32(maxSize))
return false;
e.finishSection(offset);

View File

@ -6,7 +6,7 @@ if (!wasmIsSupported())
function testLoad(type, ext, base, offset, align, expect) {
assertEq(wasmEvalText(
'(module' +
' (memory 0x10000' +
' (memory 1' +
' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
' )' +
@ -23,7 +23,7 @@ function testLoad(type, ext, base, offset, align, expect) {
function testStore(type, ext, base, offset, align, value) {
assertEq(wasmEvalText(
'(module' +
' (memory 0x10000' +
' (memory 1' +
' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
' )' +
@ -41,7 +41,7 @@ function testStore(type, ext, base, offset, align, value) {
function testLoadError(type, ext, base, offset, align, errorMsg) {
assertErrorMessage(() => wasmEvalText(
'(module' +
' (memory 0x10000' +
' (memory 1' +
' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
' )' +
@ -58,7 +58,7 @@ function testLoadError(type, ext, base, offset, align, errorMsg) {
function testStoreError(type, ext, base, offset, align, errorMsg) {
assertErrorMessage(() => wasmEvalText(
'(module' +
' (memory 0x10000' +
' (memory 1' +
' (segment 0 "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")' +
' (segment 16 "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")' +
' )' +
@ -100,7 +100,7 @@ testLoad('i32', '16_u', 16, 0, 0, 0xf1f0);
// When these tests fail, uncomment the load/store tests below.
function testLoadNYI(ext) {
assertErrorMessage(() => wasmEvalText(`(module (memory 0x10000) (func (i64.load${ext} (i32.const 0))))`), TypeError, /NYI/);
assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.load${ext} (i32.const 0))))`), TypeError, /NYI/);
}
testLoadNYI('');
testLoadNYI('8_s');
@ -122,7 +122,7 @@ testStore('i32', '', 0, 0, 0, -0x3f3e2c2c);
//testStore('i32', '', 1, 1, 4, 0xc0c1d3d4); // TODO: offset NYI
function testStoreNYI(ext) {
assertErrorMessage(() => wasmEvalText(`(module (memory 0x10000) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /NYI/);
assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /NYI/);
}
testStoreNYI('');
testStoreNYI('8');
@ -151,11 +151,11 @@ testStore('i32', '16', 0, 0, 0, 0x2345);
testLoadError('i32', '', 0, 0, 3, /memory access alignment must be a power of two/);
testStoreError('i32', '', 0, 0, 3, /memory access alignment must be a power of two/);
assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f64"));
assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "f64"));
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f64"));
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "f64"));
assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "f32"));
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))'), TypeError, mismatchError("i32", "f32"));
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "f32"));
assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "i32"));
assertErrorMessage(() => wasmEvalText('(module (memory 0x10000) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "i32"));
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "i32"));
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))'), TypeError, mismatchError("f64", "i32"));

View File

@ -132,34 +132,32 @@ wasmEvalText('(module (import $foo "a" "" (result f64)))', {a: ()=> {}});
// ----------------------------------------------------------------------------
// memory
wasmEvalText('(module (memory 65536))');
wasmEvalText('(module (memory 131072))');
assertErrorMessage(() => wasmEvalText('(module (memory 0))'), TypeError, /not a multiple of 0x10000/);
assertErrorMessage(() => wasmEvalText('(module (memory 1))'), TypeError, /not a multiple of 0x10000/);
assertErrorMessage(() => wasmEvalText('(module (memory 65535))'), TypeError, /not a multiple of 0x10000/);
assertErrorMessage(() => wasmEvalText('(module (memory 131071))'), TypeError, /not a multiple of 0x10000/);
assertErrorMessage(() => wasmEvalText('(module (memory 2147483648))'), TypeError, /initial memory size too big/);
wasmEvalText('(module (memory 0))');
wasmEvalText('(module (memory 1))');
assertErrorMessage(() => wasmEvalText('(module (memory 65536))'), TypeError, /initial memory size too big/);
assertErrorMessage(() => wasmEvalText('(module (memory 32768))'), TypeError, /initial memory size too big/);
// May OOM, but must not crash:
try {
wasmEvalText('(module (memory 2147418112))');
wasmEvalText('(module (memory 32767))');
} catch (e) {
print(e);
assertEq(String(e).indexOf("out of memory") != -1, true);
}
assertErrorMessage(() => wasmEvalText('(module (export "" memory))'), TypeError, /no memory section/);
var buf = wasmEvalText('(module (memory 65536) (export "" memory))');
var buf = wasmEvalText('(module (memory 1) (export "" memory))');
assertEq(buf instanceof ArrayBuffer, true);
assertEq(buf.byteLength, 65536);
assertErrorMessage(() => wasmEvalText('(module (memory 65536) (export "a" memory) (export "a" memory))'), TypeError, /duplicate export/);
assertErrorMessage(() => wasmEvalText('(module (memory 65536) (func) (export "a" memory) (export "a" 0))'), TypeError, /duplicate export/);
var {a, b} = wasmEvalText('(module (memory 65536) (export "a" memory) (export "b" memory))');
assertErrorMessage(() => wasmEvalText('(module (memory 1) (export "a" memory) (export "a" memory))'), TypeError, /duplicate export/);
assertErrorMessage(() => wasmEvalText('(module (memory 1) (func) (export "a" memory) (export "a" 0))'), TypeError, /duplicate export/);
var {a, b} = wasmEvalText('(module (memory 1) (export "a" memory) (export "b" memory))');
assertEq(a instanceof ArrayBuffer, true);
assertEq(a, b);
var obj = wasmEvalText('(module (memory 65536) (func (result i32) (i32.const 42)) (func (nop)) (export "a" memory) (export "b" 0) (export "c" 1))');
var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "a" memory) (export "b" 0) (export "c" 1))');
assertEq(obj.a instanceof ArrayBuffer, true);
assertEq(obj.b instanceof Function, true);
assertEq(obj.c instanceof Function, true);
@ -167,7 +165,7 @@ assertEq(obj.a.byteLength, 65536);
assertEq(obj.b(), 42);
assertEq(obj.c(), undefined);
var obj = wasmEvalText('(module (memory 65536) (func (result i32) (i32.const 42)) (export "" memory) (export "a" 0) (export "b" 0))');
var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (export "" memory) (export "a" 0) (export "b" 0))');
assertEq(obj instanceof ArrayBuffer, true);
assertEq(obj.a instanceof Function, true);
assertEq(obj.b instanceof Function, true);
@ -175,26 +173,26 @@ assertEq(obj.a, obj.b);
assertEq(obj.byteLength, 65536);
assertEq(obj.a(), 42);
var buf = wasmEvalText('(module (memory 65536 (segment 0 "")) (export "" memory))');
var buf = wasmEvalText('(module (memory 1 (segment 0 "")) (export "" memory))');
assertEq(new Uint8Array(buf)[0], 0);
var buf = wasmEvalText('(module (memory 65536 (segment 65536 "")) (export "" memory))');
var buf = wasmEvalText('(module (memory 1 (segment 65536 "")) (export "" memory))');
assertEq(new Uint8Array(buf)[0], 0);
var buf = wasmEvalText('(module (memory 65536 (segment 0 "a")) (export "" memory))');
var buf = wasmEvalText('(module (memory 1 (segment 0 "a")) (export "" memory))');
assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
var buf = wasmEvalText('(module (memory 65536 (segment 0 "a") (segment 2 "b")) (export "" memory))');
var buf = wasmEvalText('(module (memory 1 (segment 0 "a") (segment 2 "b")) (export "" memory))');
assertEq(new Uint8Array(buf)[0], 'a'.charCodeAt(0));
assertEq(new Uint8Array(buf)[1], 0);
assertEq(new Uint8Array(buf)[2], 'b'.charCodeAt(0));
var buf = wasmEvalText('(module (memory 65536 (segment 65535 "c")) (export "" memory))');
var buf = wasmEvalText('(module (memory 1 (segment 65535 "c")) (export "" memory))');
assertEq(new Uint8Array(buf)[0], 0);
assertEq(new Uint8Array(buf)[65535], 'c'.charCodeAt(0));
assertErrorMessage(() => wasmEvalText('(module (memory 65536 (segment 65536 "a")) (export "" memory))'), TypeError, /data segment does not fit/);
assertErrorMessage(() => wasmEvalText('(module (memory 65536 (segment 65535 "ab")) (export "" memory))'), TypeError, /data segment does not fit/);
assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65536 "a")) (export "" memory))'), TypeError, /data segment does not fit/);
assertErrorMessage(() => wasmEvalText('(module (memory 1 (segment 65535 "ab")) (export "" memory))'), TypeError, /data segment does not fit/);
// ----------------------------------------------------------------------------
// locals