зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1259295 - BaldrMonkey: Postorder (r=luke)
MozReview-Commit-ID: ImqMOvb2B4o --HG-- extra : rebase_source : b41c64be0480ea787fadedde98b2173a6aa0485c
This commit is contained in:
Родитель
c9cda033c2
Коммит
4a962a9584
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче