Bug 1259295 - BaldrMonkey: Postorder (r=luke)

MozReview-Commit-ID: ImqMOvb2B4o

--HG--
extra : rebase_source : b41c64be0480ea787fadedde98b2173a6aa0485c
This commit is contained in:
Dan Gohman 2016-04-28 10:36:22 -05:00
Родитель c9cda033c2
Коммит 4a962a9584
17 изменённых файлов: 4401 добавлений и 2681 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -25,7 +25,7 @@ namespace js {
namespace wasm {
static const uint32_t MagicNumber = 0x6d736100; // "\0asm"
static const uint32_t EncodingVersion = 0xa;
static const uint32_t EncodingVersion = 0x0b;
static const char SignaturesId[] = "signatures";
static const char ImportTableId[] = "import_table";
@ -36,7 +36,7 @@ static const char ExportTableId[] = "export_table";
static const char FunctionBodiesId[] = "function_bodies";
static const char DataSegmentsId[] = "data_segments";
enum class ValType
enum class ValType : uint8_t
{
// 0x00 is reserved for ExprType::Void in the binary encoding. See comment
// below about ExprType going away.
@ -64,24 +64,25 @@ enum class Expr
Block = 0x01,
Loop = 0x02,
If = 0x03,
IfElse = 0x04,
Else = 0x04,
Select = 0x05,
Br = 0x06,
BrIf = 0x07,
BrTable = 0x08,
Return = 0x14,
Unreachable = 0x15,
Return = 0x09,
Unreachable = 0x0a,
End = 0x0f,
// Basic operators
I32Const = 0x0a,
I64Const = 0x0b,
F64Const = 0x0c,
F32Const = 0x0d,
GetLocal = 0x0e,
SetLocal = 0x0f,
Call = 0x12,
CallIndirect = 0x13,
CallImport = 0x1f,
I32Const = 0x10,
I64Const = 0x11,
F64Const = 0x12,
F32Const = 0x13,
GetLocal = 0x14,
SetLocal = 0x15,
Call = 0x16,
CallIndirect = 0x17,
CallImport = 0x18,
// Memory-related operators
I32Load8S = 0x20,
@ -107,7 +108,7 @@ enum class Expr
I64Store = 0x34,
F32Store = 0x35,
F64Store = 0x36,
MemorySize = 0x3b,
CurrentMemory = 0x3b,
GrowMemory = 0x39,
// i32 operators
@ -252,8 +253,7 @@ enum class Expr
// compiling asm.js and are rejected by wasm validation.
// asm.js-specific operators
Id = 0xc0,
LoadGlobal,
LoadGlobal = 0xc0,
StoreGlobal,
I32Min,
I32Max,
@ -316,7 +316,7 @@ enum class Expr
// generalized to a list of ValType and this enum will go away, replaced,
// wherever it is used, by a varU32 + list of ValType.
enum class ExprType
enum class ExprType : uint8_t
{
Void = 0x00,
I32 = uint8_t(ValType::I32),
@ -464,15 +464,6 @@ class Encoder
// Variable-length encodings that allow back-patching.
MOZ_WARN_UNUSED_RESULT bool writePatchableFixedU8(size_t* offset) {
*offset = bytes_.length();
return bytes_.append(0xff);
}
void patchFixedU8(size_t offset, uint8_t i) {
MOZ_ASSERT(bytes_[offset] == 0xff);
bytes_[offset] = i;
}
MOZ_WARN_UNUSED_RESULT bool writePatchableVarU32(size_t* offset) {
*offset = bytes_.length();
return writeVarU32(UINT32_MAX);
@ -481,16 +472,6 @@ class Encoder
return patchVarU32(offset, patchBits, UINT32_MAX);
}
MOZ_WARN_UNUSED_RESULT bool writePatchableOneByteExpr(size_t* offset) {
*offset = bytes_.length();
return writeFixedU8(0xff);
}
void patchOneByteExpr(size_t offset, Expr expr) {
MOZ_ASSERT(size_t(expr) < UINT8_MAX);
MOZ_ASSERT(bytes_[offset] == 0xff);
bytes_[offset] = uint8_t(expr);
}
// Byte ranges start with an LEB128 length followed by an arbitrary sequence
// of bytes. When used for strings, bytes are to be interpreted as utf8.
@ -834,12 +815,15 @@ class Decoder
? Expr(u8)
: Expr(uncheckedReadFixedU8() + UINT8_MAX);
}
Expr uncheckedPeekExpr() {
static_assert(size_t(Expr::Limit) <= ExprLimit, "fits");
uint8_t u8 = cur_[0];
return u8 != UINT8_MAX
? Expr(u8)
: Expr(cur_[1] + UINT8_MAX);
void uncheckedReadFixedI32x4(I32x4* i32x4) {
struct T { I32x4 v; };
T t = uncheckedRead<T>();
memcpy(i32x4, &t, sizeof(t));
}
void uncheckedReadFixedF32x4(F32x4* f32x4) {
struct T { F32x4 v; };
T t = uncheckedRead<T>();
memcpy(f32x4, &t, sizeof(t));
}
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1000,7 +1000,7 @@ RenderExpr(WasmRenderContext& c)
return RenderLoop(c);
case Expr::If:
return RenderIfElse(c, false);
case Expr::IfElse:
case Expr::Else:
return RenderIfElse(c, true);
case Expr::I32Clz:
case Expr::I32Ctz:
@ -1791,7 +1791,11 @@ wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuf
WasmRenderContext c(cx, d, buffer);
if (!RenderModule(c)) {
if (!c.buffer.append("Binary-to-text is temporarily unavailable\n"))
return false;
// FIXME: Implement binary-to-text and re-enable this.
if (0 && !RenderModule(c)) {
if (!cx->isExceptionPending())
ReportOutOfMemory(cx);
return false;

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/EnumeratedRange.h"
#include "asmjs/WasmIonCompile.h"
#include "asmjs/WasmStubs.h"
#include "jit/MacroAssembler-inl.h"
@ -54,7 +55,8 @@ ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
tasks_(cx),
freeTasks_(cx),
activeFunc_(nullptr),
finishedFuncs_(false)
startedFuncDefs_(false),
finishedFuncDefs_(false)
{
MOZ_ASSERT(IsCompilingAsmJS());
}
@ -563,9 +565,9 @@ ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* g
}
bool
ModuleGenerator::allocateGlobalVar(ValType type, bool isConst, uint32_t* index)
ModuleGenerator::allocateGlobal(ValType type, bool isConst, uint32_t* index)
{
MOZ_ASSERT(!startedFuncDefs());
MOZ_ASSERT(!startedFuncDefs_);
unsigned width = 0;
switch (type) {
case ValType::I32:
@ -591,7 +593,7 @@ ModuleGenerator::allocateGlobalVar(ValType type, bool isConst, uint32_t* index)
return false;
*index = shared_->globals.length();
return shared_->globals.append(AsmJSGlobalVariable(ToExprType(type), offset, isConst));
return shared_->globals.append(GlobalDesc(type, offset, isConst));
}
void
@ -731,10 +733,8 @@ ModuleGenerator::addMemoryExport(UniqueChars fieldName)
bool
ModuleGenerator::startFuncDefs()
{
MOZ_ASSERT(!startedFuncDefs());
threadView_ = MakeUnique<ModuleGeneratorThreadView>(*shared_);
if (!threadView_)
return false;
MOZ_ASSERT(!startedFuncDefs_);
MOZ_ASSERT(!finishedFuncDefs_);
uint32_t numTasks;
if (ParallelCompilationEnabled(cx_) &&
@ -759,23 +759,24 @@ ModuleGenerator::startFuncDefs()
return false;
JSRuntime* rt = cx_->compartment()->runtimeFromAnyThread();
for (size_t i = 0; i < numTasks; i++)
tasks_.infallibleEmplaceBack(rt, *threadView_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
tasks_.infallibleEmplaceBack(rt, *shared_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
if (!freeTasks_.reserve(numTasks))
return false;
for (size_t i = 0; i < numTasks; i++)
freeTasks_.infallibleAppend(&tasks_[i]);
MOZ_ASSERT(startedFuncDefs());
startedFuncDefs_ = true;
MOZ_ASSERT(!finishedFuncDefs_);
return true;
}
bool
ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg)
{
MOZ_ASSERT(startedFuncDefs());
MOZ_ASSERT(startedFuncDefs_);
MOZ_ASSERT(!activeFunc_);
MOZ_ASSERT(!finishedFuncs_);
MOZ_ASSERT(!finishedFuncDefs_);
if (freeTasks_.empty() && !finishOutstandingTask())
return false;
@ -827,9 +828,9 @@ ModuleGenerator::finishFuncDef(uint32_t funcIndex, unsigned generateTime, Functi
bool
ModuleGenerator::finishFuncDefs()
{
MOZ_ASSERT(startedFuncDefs());
MOZ_ASSERT(startedFuncDefs_);
MOZ_ASSERT(!activeFunc_);
MOZ_ASSERT(!finishedFuncs_);
MOZ_ASSERT(!finishedFuncDefs_);
while (outstanding_ > 0) {
if (!finishOutstandingTask())
@ -840,7 +841,7 @@ ModuleGenerator::finishFuncDefs()
MOZ_ASSERT(funcIsDefined(funcIndex));
module_->functionBytes = masm_.size();
finishedFuncs_ = true;
finishedFuncDefs_ = true;
return true;
}
@ -883,7 +884,7 @@ ModuleGenerator::finish(CacheableCharsVector&& prettyFuncNames,
SlowFunctionVector* slowFuncs)
{
MOZ_ASSERT(!activeFunc_);
MOZ_ASSERT(finishedFuncs_);
MOZ_ASSERT(finishedFuncDefs_);
UniqueStaticLinkData link = MakeUnique<StaticLinkData>();
if (!link)

Просмотреть файл

@ -20,7 +20,6 @@
#define wasm_generator_h
#include "asmjs/WasmBinary.h"
#include "asmjs/WasmIonCompile.h"
#include "asmjs/WasmModule.h"
#include "jit/MacroAssembler.h"
@ -47,12 +46,11 @@ struct SlowFunction
typedef Vector<SlowFunction> SlowFunctionVector;
// The ModuleGeneratorData holds all the state shared between the
// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData
// is encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
// present a race-free interface to the code in each thread assuming any given
// element is initialized by the ModuleGenerator thread before an index to that
// element is written to Bytes sent to a ModuleGeneratorThreadView thread.
// Once created, the Vectors are never resized.
// ModuleGenerator thread and background compile threads. The background
// threads are given a read-only view of the ModuleGeneratorData and the
// ModuleGenerator is careful to initialize, and never subsequently mutate,
// any given datum before being read by a background thread. In particular,
// once created, the Vectors are never resized.
struct TableModuleGeneratorData
{
@ -82,18 +80,6 @@ struct ImportModuleGeneratorData
typedef Vector<ImportModuleGeneratorData, 0, SystemAllocPolicy> ImportModuleGeneratorDataVector;
struct AsmJSGlobalVariable
{
ExprType type;
unsigned globalDataOffset;
bool isConst;
AsmJSGlobalVariable(ExprType type, unsigned offset, bool isConst)
: type(type), globalDataOffset(offset), isConst(isConst)
{}
};
typedef Vector<AsmJSGlobalVariable, 0, SystemAllocPolicy> AsmJSGlobalVariableVector;
struct ModuleGeneratorData
{
CompileArgs args;
@ -105,7 +91,7 @@ struct ModuleGeneratorData
TableModuleGeneratorDataVector sigToTable;
DeclaredSigPtrVector funcSigs;
ImportModuleGeneratorDataVector imports;
AsmJSGlobalVariableVector globals;
GlobalDescVector globals;
uint32_t funcSigIndex(uint32_t funcIndex) const {
return funcSigs[funcIndex] - sigs.begin();
@ -118,51 +104,6 @@ struct ModuleGeneratorData
typedef UniquePtr<ModuleGeneratorData> UniqueModuleGeneratorData;
// The ModuleGeneratorThreadView class presents a restricted, read-only view of
// the shared state needed by helper threads. There is only one
// ModuleGeneratorThreadView object owned by ModuleGenerator and referenced by
// all compile tasks.
class ModuleGeneratorThreadView
{
const ModuleGeneratorData& shared_;
public:
explicit ModuleGeneratorThreadView(const ModuleGeneratorData& shared)
: shared_(shared)
{}
CompileArgs args() const {
return shared_.args;
}
bool isAsmJS() const {
return shared_.kind == ModuleKind::AsmJS;
}
uint32_t numTableElems() const {
MOZ_ASSERT(!isAsmJS());
return shared_.numTableElems;
}
uint32_t minHeapLength() const {
return shared_.minHeapLength;
}
const DeclaredSig& sig(uint32_t sigIndex) const {
return shared_.sigs[sigIndex];
}
const TableModuleGeneratorData& sigToTable(uint32_t sigIndex) const {
return shared_.sigToTable[sigIndex];
}
const DeclaredSig& funcSig(uint32_t funcIndex) const {
MOZ_ASSERT(shared_.funcSigs[funcIndex]);
return *shared_.funcSigs[funcIndex];
}
const ImportModuleGeneratorData& import(uint32_t importIndex) const {
MOZ_ASSERT(shared_.imports[importIndex].sig);
return shared_.imports[importIndex];
}
const AsmJSGlobalVariable& globalVar(uint32_t globalIndex) const {
return shared_.globals[globalIndex];
}
};
// A ModuleGenerator encapsulates the creation of a wasm module. During the
// lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created
// and destroyed to compile the individual function bodies. After generating all
@ -171,7 +112,6 @@ class ModuleGeneratorThreadView
class MOZ_STACK_CLASS ModuleGenerator
{
typedef UniquePtr<ModuleGeneratorThreadView> UniqueModuleGeneratorThreadView;
typedef HashMap<uint32_t, uint32_t> FuncIndexMap;
ExclusiveContext* cx_;
@ -197,13 +137,13 @@ class MOZ_STACK_CLASS ModuleGenerator
// Parallel compilation
bool parallel_;
uint32_t outstanding_;
UniqueModuleGeneratorThreadView threadView_;
Vector<IonCompileTask> tasks_;
Vector<IonCompileTask*> freeTasks_;
// Assertions
FunctionGenerator* activeFunc_;
bool finishedFuncs_;
DebugOnly<FunctionGenerator*> activeFunc_;
DebugOnly<bool> startedFuncDefs_;
DebugOnly<bool> finishedFuncDefs_;
bool finishOutstandingTask();
bool funcIsDefined(uint32_t funcIndex) const;
@ -213,7 +153,6 @@ class MOZ_STACK_CLASS ModuleGenerator
bool finishCodegen(StaticLinkData* link);
bool finishStaticLinkData(uint8_t* code, uint32_t codeBytes, StaticLinkData* link);
bool addImport(const Sig& sig, uint32_t globalDataOffset);
bool startedFuncDefs() const { return !!threadView_; }
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
public:
@ -238,6 +177,10 @@ class MOZ_STACK_CLASS ModuleGenerator
uint32_t numFuncSigs() const { return module_->numFuncs; }
const DeclaredSig& funcSig(uint32_t funcIndex) const;
// Globals:
bool allocateGlobal(ValType type, bool isConst, uint32_t* index);
const GlobalDesc& global(unsigned index) const { return shared_->globals[index]; }
// Imports:
uint32_t numImports() const;
const ImportModuleGeneratorData& import(uint32_t index) const;
@ -264,10 +207,6 @@ class MOZ_STACK_CLASS ModuleGenerator
void initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices);
void bumpMinHeapLength(uint32_t newMinHeapLength);
// asm.js global variables:
bool allocateGlobalVar(ValType type, bool isConst, uint32_t* index);
const AsmJSGlobalVariable& globalVar(unsigned index) const { return shared_->globals[index]; }
// Return a ModuleData object which may be used to construct a Module, the
// StaticLinkData required to call Module::staticallyLink, and the list of
// functions that took a long time to compile.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -25,7 +25,7 @@
namespace js {
namespace wasm {
class ModuleGeneratorThreadView;
struct ModuleGeneratorData;
typedef Vector<jit::MIRType, 8, SystemAllocPolicy> MIRTypeVector;
typedef jit::ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
@ -108,7 +108,7 @@ class FuncCompileResults
class IonCompileTask
{
JSRuntime* const runtime_;
ModuleGeneratorThreadView& mg_;
const ModuleGeneratorData& mg_;
LifoAlloc lifo_;
UniqueFuncBytes func_;
Maybe<FuncCompileResults> results_;
@ -117,7 +117,7 @@ class IonCompileTask
IonCompileTask& operator=(const IonCompileTask&) = delete;
public:
IonCompileTask(JSRuntime* rt, ModuleGeneratorThreadView& mg, size_t defaultChunkSize)
IonCompileTask(JSRuntime* rt, const ModuleGeneratorData& mg, size_t defaultChunkSize)
: runtime_(rt), mg_(mg), lifo_(defaultChunkSize), func_(nullptr)
{}
JSRuntime* runtime() const {
@ -126,7 +126,7 @@ class IonCompileTask
LifoAlloc& lifo() {
return lifo_;
}
ModuleGeneratorThreadView& mg() const {
const ModuleGeneratorData& mg() const {
return mg_;
}
void init(UniqueFuncBytes func) {

Просмотреть файл

@ -20,6 +20,8 @@
#include "mozilla/ArrayUtils.h"
#include "asmjs/WasmIonCompile.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;

Просмотреть файл

@ -305,8 +305,8 @@ class WasmAstBlock : public WasmAstExpr
public:
static const WasmAstExprKind Kind = WasmAstExprKind::Block;
explicit WasmAstBlock(Expr expr, WasmName breakName, WasmName continueName,
WasmAstExprVector&& exprs)
explicit WasmAstBlock(Expr expr, WasmName breakName,
WasmName continueName, WasmAstExprVector&& exprs)
: WasmAstExpr(Kind),
expr_(expr),
breakName_(breakName),
@ -1004,7 +1004,7 @@ IsWasmLetter(char16_t c)
static bool
IsNameAfterDollar(char16_t c)
{
return IsWasmLetter(c) || IsWasmDigit(c) || c == '_' || c == '$' || c == '-';
return IsWasmLetter(c) || IsWasmDigit(c) || c == '_' || c == '$' || c == '-' || c == '.';
}
static bool
@ -3481,9 +3481,18 @@ ResolveConversionOperator(Resolver& r, WasmAstConversionOperator& b)
static bool
ResolveIfElse(Resolver& r, WasmAstIf& i)
{
return ResolveExpr(r, i.cond()) &&
ResolveExpr(r, i.thenBranch()) &&
(!i.hasElse() || ResolveExpr(r, i.elseBranch()));
if (!ResolveExpr(r, i.cond()))
return false;
if (!r.pushTarget(WasmName()))
return false;
if (!ResolveExpr(r, i.thenBranch()))
return false;
if (i.hasElse()) {
if (!ResolveExpr(r, i.elseBranch()))
return false;
}
r.popTarget(WasmName());
return true;
}
static bool
@ -3654,14 +3663,15 @@ EncodeBlock(Encoder& e, WasmAstBlock& b)
return false;
size_t numExprs = b.exprs().length();
if (!e.writeVarU32(numExprs))
return false;
for (size_t i = 0; i < numExprs; i++) {
if (!EncodeExpr(e, *b.exprs()[i]))
return false;
}
if (!e.writeExpr(Expr::End))
return false;
return true;
}
@ -3670,20 +3680,25 @@ EncodeBranch(Encoder& e, WasmAstBranch& br)
{
MOZ_ASSERT(br.expr() == Expr::Br || br.expr() == Expr::BrIf);
if (!e.writeExpr(br.expr()))
return false;
if (!e.writeVarU32(br.target().index()))
return false;
if (br.maybeValue() ? !EncodeExpr(e, *br.maybeValue()) : !e.writeExpr(Expr::Nop))
return false;
if (br.maybeValue()) {
if (!EncodeExpr(e, *br.maybeValue()))
return false;
} else {
if (!e.writeExpr(Expr::Nop))
return false;
}
if (br.expr() == Expr::BrIf) {
if (!EncodeExpr(e, br.cond()))
return false;
}
if (!e.writeExpr(br.expr()))
return false;
if (!e.writeVarU32(br.target().index()))
return false;
return true;
}
@ -3701,33 +3716,33 @@ EncodeArgs(Encoder& e, const WasmAstExprVector& args)
static bool
EncodeCall(Encoder& e, WasmAstCall& c)
{
if (!EncodeArgs(e, c.args()))
return false;
if (!e.writeExpr(c.expr()))
return false;
if (!e.writeVarU32(c.func().index()))
return false;
if (!EncodeArgs(e, c.args()))
return false;
return true;
}
static bool
EncodeCallIndirect(Encoder& e, WasmAstCallIndirect& c)
{
if (!e.writeExpr(Expr::CallIndirect))
return false;
if (!e.writeVarU32(c.sig().index()))
return false;
if (!EncodeExpr(e, *c.index()))
return false;
if (!EncodeArgs(e, c.args()))
return false;
if (!e.writeExpr(Expr::CallIndirect))
return false;
if (!e.writeVarU32(c.sig().index()))
return false;
return true;
}
@ -3763,92 +3778,112 @@ EncodeGetLocal(Encoder& e, WasmAstGetLocal& gl)
static bool
EncodeSetLocal(Encoder& e, WasmAstSetLocal& sl)
{
return e.writeExpr(Expr::SetLocal) &&
e.writeVarU32(sl.local().index()) &&
EncodeExpr(e, sl.value());
return EncodeExpr(e, sl.value()) &&
e.writeExpr(Expr::SetLocal) &&
e.writeVarU32(sl.local().index());
}
static bool
EncodeUnaryOperator(Encoder& e, WasmAstUnaryOperator& b)
{
return e.writeExpr(b.expr()) &&
EncodeExpr(e, *b.op());
return EncodeExpr(e, *b.op()) &&
e.writeExpr(b.expr());
}
static bool
EncodeBinaryOperator(Encoder& e, WasmAstBinaryOperator& b)
{
return e.writeExpr(b.expr()) &&
EncodeExpr(e, *b.lhs()) &&
EncodeExpr(e, *b.rhs());
return EncodeExpr(e, *b.lhs()) &&
EncodeExpr(e, *b.rhs()) &&
e.writeExpr(b.expr());
}
static bool
EncodeTernaryOperator(Encoder& e, WasmAstTernaryOperator& b)
{
return e.writeExpr(b.expr()) &&
EncodeExpr(e, *b.op0()) &&
return EncodeExpr(e, *b.op0()) &&
EncodeExpr(e, *b.op1()) &&
EncodeExpr(e, *b.op2());
EncodeExpr(e, *b.op2()) &&
e.writeExpr(b.expr());
}
static bool
EncodeComparisonOperator(Encoder& e, WasmAstComparisonOperator& b)
{
return e.writeExpr(b.expr()) &&
EncodeExpr(e, *b.lhs()) &&
EncodeExpr(e, *b.rhs());
return EncodeExpr(e, *b.lhs()) &&
EncodeExpr(e, *b.rhs()) &&
e.writeExpr(b.expr());
}
static bool
EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b)
{
return e.writeExpr(b.expr()) &&
EncodeExpr(e, *b.op());
return EncodeExpr(e, *b.op()) &&
e.writeExpr(b.expr());
}
static bool
EmitIf(Encoder& e, WasmAstIf& i)
{
return e.writeExpr(i.hasElse() ? Expr::IfElse : Expr::If) &&
EncodeExpr(e, i.cond()) &&
return EncodeExpr(e, i.cond()) &&
e.writeExpr(Expr::If) &&
EncodeExpr(e, i.thenBranch()) &&
(!i.hasElse() || EncodeExpr(e, i.elseBranch()));
(!i.hasElse() ||
(e.writeExpr(Expr::Else) &&
EncodeExpr(e, i.elseBranch()))) &&
e.writeExpr(Expr::End);
}
static bool
EncodeLoadStoreAddress(Encoder &e, const WasmAstLoadStoreAddress &address)
{
return EncodeExpr(e, address.base());
}
static bool
EncodeLoadStoreFlags(Encoder &e, const WasmAstLoadStoreAddress &address)
{
return e.writeVarU32(address.flags()) &&
e.writeVarU32(address.offset()) &&
EncodeExpr(e, address.base());
e.writeVarU32(address.offset());
}
static bool
EncodeLoad(Encoder& e, WasmAstLoad& l)
{
return e.writeExpr(l.expr()) &&
EncodeLoadStoreAddress(e, l.address());
return EncodeLoadStoreAddress(e, l.address()) &&
e.writeExpr(l.expr()) &&
EncodeLoadStoreFlags(e, l.address());
}
static bool
EncodeStore(Encoder& e, WasmAstStore& s)
{
return e.writeExpr(s.expr()) &&
EncodeLoadStoreAddress(e, s.address()) &&
EncodeExpr(e, s.value());
return EncodeLoadStoreAddress(e, s.address()) &&
EncodeExpr(e, s.value()) &&
e.writeExpr(s.expr()) &&
EncodeLoadStoreFlags(e, s.address());
}
static bool
EncodeReturn(Encoder& e, WasmAstReturn& r)
{
return e.writeExpr(Expr::Return) &&
(!r.maybeExpr() || EncodeExpr(e, *r.maybeExpr()));
if (r.maybeExpr()) {
if (!EncodeExpr(e, *r.maybeExpr()))
return false;
} else {
if (!e.writeExpr(Expr::Nop))
return false;
}
return e.writeExpr(Expr::Return);
}
static bool
EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt)
{
if (!EncodeExpr(e, bt.index()))
return false;
if (!e.writeExpr(Expr::BrTable))
return false;
@ -3863,7 +3898,7 @@ EncodeBranchTable(Encoder& e, WasmAstBranchTable& bt)
if (!e.writeFixedU32(bt.def().index()))
return false;
return EncodeExpr(e, bt.index());
return true;
}
static bool

Просмотреть файл

@ -39,6 +39,7 @@ class PropertyName;
namespace wasm {
using mozilla::DebugOnly;
using mozilla::EnumeratedArray;
using mozilla::Maybe;
using mozilla::Move;
@ -48,6 +49,24 @@ typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector;
// ValType/ExprType utilities
// ExprType::Limit is an out-of-band value and has no wasm-semantic meaning. For
// the purpose of recursive validation, we use this value to represent the type
// of branch/return instructions that don't actually return to the parent
// expression and can thus be used in any context.
const ExprType AnyType = ExprType::Limit;
inline ExprType
Unify(ExprType a, ExprType b)
{
if (a == AnyType)
return b;
if (b == AnyType)
return a;
if (a == b)
return a;
return ExprType::Void;
}
static inline bool
IsVoid(ExprType et)
{
@ -73,6 +92,50 @@ IsSimdType(ValType vt)
return vt == ValType::I32x4 || vt == ValType::F32x4 || vt == ValType::B32x4;
}
static inline uint32_t
NumSimdElements(ValType vt)
{
MOZ_ASSERT(IsSimdType(vt));
switch (vt) {
case ValType::I32x4:
case ValType::F32x4:
case ValType::B32x4:
return 4;
default:
MOZ_CRASH("Unhandled SIMD type");
}
}
static inline ValType
SimdElementType(ValType vt)
{
MOZ_ASSERT(IsSimdType(vt));
switch (vt) {
case ValType::I32x4:
return ValType::I32;
case ValType::F32x4:
return ValType::F32;
case ValType::B32x4:
return ValType::I32;
default:
MOZ_CRASH("Unhandled SIMD type");
}
}
static inline ValType
SimdBoolType(ValType vt)
{
MOZ_ASSERT(IsSimdType(vt));
switch (vt) {
case ValType::I32x4:
case ValType::F32x4:
case ValType::B32x4:
return ValType::B32x4;
default:
MOZ_CRASH("Unhandled SIMD type");
}
}
static inline bool
IsSimdType(ExprType et)
{
@ -233,6 +296,21 @@ struct SigHashPolicy
static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; }
};
// A GlobalDesc describes a single global variable. Currently, globals are only
// exposed through asm.js.
struct GlobalDesc
{
ValType type;
unsigned globalDataOffset;
bool isConst;
GlobalDesc(ValType type, unsigned offset, bool isConst)
: type(type), globalDataOffset(offset), isConst(isConst)
{}
};
typedef Vector<GlobalDesc, 0, SystemAllocPolicy> GlobalDescVector;
// A "declared" signature is a Sig object that is created and owned by the
// ModuleGenerator. These signature objects are read-only and have the same
// lifetime as the ModuleGenerator. This type is useful since some uses of Sig

Просмотреть файл

@ -56,6 +56,14 @@ assertEq(f(-1), (1048575*-1)|0);
assertEq(f(INT32_MIN), (1048575*INT32_MIN)|0);
assertEq(f(INT32_MAX), (1048575*INT32_MAX)|0);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0; j=~i; return j|0 } return f"));
assertEq(f(0), ~0);
assertEq(f(3), ~3);
assertEq(f(-3), ~-3);
assertEq(f(INT32_MAX), ~INT32_MAX);
assertEq(f(INT32_MIN), ~INT32_MIN);
assertEq(f(UINT32_MAX), ~UINT32_MAX);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=+i; var j=0; j=~~i; return j|0 } return f"));
assertEq(f(0), 0);
assertEq(f(3.5), 3);

Просмотреть файл

@ -273,7 +273,7 @@ assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0))
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (block (br 0 (f32.const 42)))))'), TypeError, mismatchError("f32", "i32"));
assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`), TypeError, mismatchError("void", "i32"));
assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`), TypeError, mismatchError("void", "i32"));
assertErrorMessage(() => wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (f32.const 42)))) (export "" 0))`), TypeError, mismatchError("f32", "i32"));
assertEq(wasmEvalText('(module (func (result i32) (block (br 0 (i32.const 42)) (i32.const 13))) (export "" 0))')(), 42);
@ -282,6 +282,10 @@ assertEq(wasmEvalText('(module (func) (func (block (br_if 0 (call 0) (i32.const
var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (i32.const 43))) (export "" 0))`);
assertEq(f(0), 43);
assertEq(f(1), 43);
var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 1 (i32.const 42))) (i32.const 43))) (export "" 0))`);
assertEq(f(0), 43);
assertEq(f(1), 42);
var f = wasmEvalText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (i32.const 43))) (export "" 0))`);
@ -290,6 +294,10 @@ assertEq(f(1), 42);
var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 0 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`);
assertEq(f(0), 43);
assertEq(f(1), 43);
var f = wasmEvalText(`(module (func (result i32) (param i32) (block (if (get_local 0) (br 1 (i32.const 42))) (br 0 (i32.const 43)))) (export "" 0))`);
assertEq(f(0), 43);
assertEq(f(1), 42);
var f = wasmEvalText(`(module (func (result i32) (param i32) (block (br_if 0 (i32.const 42) (get_local 0)) (br 0 (i32.const 43)))) (export "" 0))`);
@ -298,6 +306,10 @@ assertEq(f(1), 42);
var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (if (get_local 0) (br 0 (i32.const 99))) (i32.const -1)))) (export "" 0))`);
assertEq(f(0), 0);
assertEq(f(1), 0);
var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (if (get_local 0) (br 1 (i32.const 99))) (i32.const -1)))) (export "" 0))`);
assertEq(f(0), 0);
assertEq(f(1), 100);
var f = wasmEvalText(`(module (func (param i32) (result i32) (i32.add (i32.const 1) (block (br_if 0 (i32.const 99) (get_local 0)) (i32.const -1)))) (export "" 0))`);

Просмотреть файл

@ -94,7 +94,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 1) (func (i64.load${ext} (i32.const 0))))`), TypeError, /NYI/);
assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.load${ext} (i32.const 0))))`), TypeError, /not yet implemented: i64/);
}
testLoadNYI('');
testLoadNYI('8_s');
@ -116,7 +116,7 @@ testStore('i32', '', 0, 1, 0, -0x3f3e2c2c);
testStore('i32', '', 1, 1, 4, -0x3f3e2c2c);
function testStoreNYI(ext) {
assertErrorMessage(() => wasmEvalText(`(module (memory 1) (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, /not yet implemented: i64/);
}
testStoreNYI('');
testStoreNYI('8');

Просмотреть файл

@ -6,8 +6,8 @@ const magic1 = 0x61; // 'a'
const magic2 = 0x73; // 's'
const magic3 = 0x6d; // 'm'
// EncodingVersion = 10 (to be changed to 1 at some point in the future)
const ver0 = 0x0a;
// EncodingVersion = 11 (unofficial; to be reset at some point in the future)
const ver0 = 0x0b;
const ver1 = 0x00;
const ver2 = 0x00;
const ver3 = 0x00;
@ -32,8 +32,8 @@ const I64Code = 2;
const F32Code = 3;
const F64Code = 4;
const NopCode = 0x00;
const BlockCode = 0x01;
const Block = 0x01;
const End = 0x0f;
function toU8(array) {
for (let b of array)
@ -209,14 +209,8 @@ assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), decl
wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0,0,0]), tableSection([0,1,0,2]), bodySection([v2vBody, v2vBody, v2vBody])]));
wasmEval(moduleWithSections([sigSection([v2vSig,i2vSig]), declSection([0,0,1]), tableSection([0,1,2]), bodySection([v2vBody, v2vBody, v2vBody])]));
// Deep nesting shouldn't crash. With iterative decoding, we should test that
// this doesn't even throw.
try {
var manyBlocks = [];
for (var i = 0; i < 20000; i++)
manyBlocks.push(BlockCode, 1);
manyBlocks.push(NopCode);
wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:manyBlocks})])]));
} catch (e) {
assertEq(String(e).indexOf("too much recursion") == -1, false);
}
// Deep nesting shouldn't crash or even throw.
var manyBlocks = [];
for (var i = 0; i < 20000; i++)
manyBlocks.push(Block, End);
wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:manyBlocks})])]));

Просмотреть файл

@ -1,6 +1,9 @@
if (!wasmIsSupported())
quit();
// FIXME: Enable this test once binary-to-text is implemented again.
quit();
load(libdir + "asserts.js");
var caught = false;