Commit 76eb976a authored by titzer's avatar titzer Committed by Commit bot

[wasm] Master CL for Binary 0xC changes.

[0xC] Convert to stack machine semantics.
[0xC] Use section codes instead of names.
[0xC] Add elements section decoding.
[0xC] Decoding of globals section.
[0xC] Decoding of memory section.
[0xC] Decoding of imports section.
[0xC] Decoding of exports section.
[0xC] Decoding of data section.
[0xC] Remove CallImport bytecode.
[0xC] Function bodies have an implicit block.
[0xC] Remove the bottom label from loops.
[0xC] Add signatures to blocks.
[0xC] Remove arities from branches.
Add tests for init expression decoding.
Rework compilation of import wrappers and how they are patched.
Rework function indices in debugging.
Fix ASM->WASM builder for stack machine.
Reorganize asm.js foreign functions due to import indices change.

R=ahaas@chromium.org,rossberg@chromium.org,bradnelson@chromium.org
BUG=chromium:575167
LOG=Y

Review-Url: https://codereview.chromium.org/2345593003
Cr-Commit-Position: refs/heads/master@{#39678}
parent 3200fafa
...@@ -207,7 +207,8 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(i::Isolate* isolate, ...@@ -207,7 +207,8 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(i::Isolate* isolate,
ErrorThrower thrower(isolate, "Asm.js -> WebAssembly instantiation"); ErrorThrower thrower(isolate, "Asm.js -> WebAssembly instantiation");
i::MaybeHandle<i::JSObject> maybe_module_object = i::MaybeHandle<i::JSObject> maybe_module_object =
i::wasm::WasmModule::Instantiate(isolate, module, foreign, memory); i::wasm::WasmModule::Instantiate(isolate, &thrower, module, foreign,
memory);
if (maybe_module_object.is_null()) { if (maybe_module_object.is_null()) {
return MaybeHandle<Object>(); return MaybeHandle<Object>();
} }
......
...@@ -128,6 +128,7 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, ...@@ -128,6 +128,7 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
script_(script), script_(script),
root_(root), root_(root),
forward_definitions_(zone), forward_definitions_(zone),
ffi_use_signatures_(zone),
stdlib_types_(zone), stdlib_types_(zone),
stdlib_math_types_(zone), stdlib_math_types_(zone),
module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)), module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)),
...@@ -329,8 +330,8 @@ AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) { ...@@ -329,8 +330,8 @@ AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
return i->second; return i->second;
} }
AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) { AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const {
ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_; const ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_;
ZoneHashMap::Entry* entry = ZoneHashMap::Entry* entry =
scope->Lookup(variable, ComputePointerHash(variable)); scope->Lookup(variable, ComputePointerHash(variable));
if (entry == nullptr && in_function_) { if (entry == nullptr && in_function_) {
...@@ -423,6 +424,8 @@ AsmType* AsmTyper::TypeOf(AstNode* node) const { ...@@ -423,6 +424,8 @@ AsmType* AsmTyper::TypeOf(AstNode* node) const {
return AsmType::None(); return AsmType::None();
} }
AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
auto* var_info = Lookup(var); auto* var_info = Lookup(var);
if (var_info == nullptr) { if (var_info == nullptr) {
...@@ -2306,10 +2309,21 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { ...@@ -2306,10 +2309,21 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
FAIL(call, "Calling something that's not a function."); FAIL(call, "Calling something that's not a function.");
} }
if (callee_type->AsFFIType() != nullptr && if (callee_type->AsFFIType() != nullptr) {
return_type == AsmType::Float()) { if (return_type == AsmType::Float()) {
FAIL(call, "Foreign functions can't return float."); FAIL(call, "Foreign functions can't return float.");
} }
// Record FFI use signature, since the asm->wasm translator must know
// all uses up-front.
ffi_use_signatures_.emplace_back(
FFIUseSignature(call_var_proxy->var(), zone_));
FFIUseSignature* sig = &ffi_use_signatures_.back();
sig->return_type_ = return_type;
sig->arg_types_.reserve(args.size());
for (size_t i = 0; i < args.size(); ++i) {
sig->arg_types_.emplace_back(args[i]);
}
}
if (!callee_type->CanBeInvokedWith(return_type, args)) { if (!callee_type->CanBeInvokedWith(return_type, args)) {
FAIL(call, "Function invocation does not match function type."); FAIL(call, "Function invocation does not match function type.");
......
...@@ -73,12 +73,26 @@ class AsmTyper final { ...@@ -73,12 +73,26 @@ class AsmTyper final {
const char* error_message() const { return error_message_; } const char* error_message() const { return error_message_; }
AsmType* TypeOf(AstNode* node) const; AsmType* TypeOf(AstNode* node) const;
AsmType* TypeOf(Variable* v) const;
StandardMember VariableAsStandardMember(Variable* var); StandardMember VariableAsStandardMember(Variable* var);
typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet; typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet;
StdlibSet StdlibUses() const { return stdlib_uses_; } StdlibSet StdlibUses() const { return stdlib_uses_; }
// Each FFI import has a usage-site signature associated with it.
struct FFIUseSignature {
Variable* var;
ZoneVector<AsmType*> arg_types_;
AsmType* return_type_;
FFIUseSignature(Variable* v, Zone* zone)
: var(v), arg_types_(zone), return_type_(nullptr) {}
};
const ZoneVector<FFIUseSignature>& FFIUseSignatures() {
return ffi_use_signatures_;
}
private: private:
friend class v8::internal::wasm::AsmTyperHarnessBuilder; friend class v8::internal::wasm::AsmTyperHarnessBuilder;
...@@ -192,7 +206,7 @@ class AsmTyper final { ...@@ -192,7 +206,7 @@ class AsmTyper final {
// Lookup(Delta, Gamma, x) // Lookup(Delta, Gamma, x)
// //
// Delta is the global_scope_ member, and Gamma, local_scope_. // Delta is the global_scope_ member, and Gamma, local_scope_.
VariableInfo* Lookup(Variable* variable); VariableInfo* Lookup(Variable* variable) const;
// All of the ValidateXXX methods below return AsmType::None() in case of // All of the ValidateXXX methods below return AsmType::None() in case of
// validation failure. // validation failure.
...@@ -306,6 +320,7 @@ class AsmTyper final { ...@@ -306,6 +320,7 @@ class AsmTyper final {
AsmType* return_type_ = nullptr; AsmType* return_type_ = nullptr;
ZoneVector<VariableInfo*> forward_definitions_; ZoneVector<VariableInfo*> forward_definitions_;
ZoneVector<FFIUseSignature> ffi_use_signatures_;
ObjectTypeMap stdlib_types_; ObjectTypeMap stdlib_types_;
ObjectTypeMap stdlib_math_types_; ObjectTypeMap stdlib_math_types_;
......
This diff is collapsed.
...@@ -778,6 +778,18 @@ void Int64Lowering::LowerNode(Node* node) { ...@@ -778,6 +778,18 @@ void Int64Lowering::LowerNode(Node* node) {
} }
break; break;
} }
case IrOpcode::kProjection: {
Node* call = node->InputAt(0);
DCHECK_EQ(IrOpcode::kCall, call->opcode());
CallDescriptor* descriptor =
const_cast<CallDescriptor*>(CallDescriptorOf(call->op()));
for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
if (descriptor->GetReturnType(i) == MachineType::Int64()) {
UNREACHABLE(); // TODO(titzer): implement multiple i64 returns.
}
}
break;
}
case IrOpcode::kWord64ReverseBytes: { case IrOpcode::kWord64ReverseBytes: {
Node* input = node->InputAt(0); Node* input = node->InputAt(0);
ReplaceNode(node, graph()->NewNode(machine()->Word32ReverseBytes().op(), ReplaceNode(node, graph()->NewNode(machine()->Word32ReverseBytes().op(),
......
...@@ -189,7 +189,14 @@ class WasmTrapHelper : public ZoneObject { ...@@ -189,7 +189,14 @@ class WasmTrapHelper : public ZoneObject {
Node* GetTrapValue(wasm::FunctionSig* sig) { Node* GetTrapValue(wasm::FunctionSig* sig) {
if (sig->return_count() > 0) { if (sig->return_count() > 0) {
switch (sig->GetReturn()) { return GetTrapValue(sig->GetReturn());
} else {
return jsgraph()->Int32Constant(0xdeadbeef);
}
}
Node* GetTrapValue(wasm::LocalType type) {
switch (type) {
case wasm::kAstI32: case wasm::kAstI32:
return jsgraph()->Int32Constant(0xdeadbeef); return jsgraph()->Int32Constant(0xdeadbeef);
case wasm::kAstI64: case wasm::kAstI64:
...@@ -197,16 +204,12 @@ class WasmTrapHelper : public ZoneObject { ...@@ -197,16 +204,12 @@ class WasmTrapHelper : public ZoneObject {
case wasm::kAstF32: case wasm::kAstF32:
return jsgraph()->Float32Constant(bit_cast<float>(0xdeadbeef)); return jsgraph()->Float32Constant(bit_cast<float>(0xdeadbeef));
case wasm::kAstF64: case wasm::kAstF64:
return jsgraph()->Float64Constant( return jsgraph()->Float64Constant(bit_cast<double>(0xdeadbeefdeadbeef));
bit_cast<double>(0xdeadbeefdeadbeef));
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
} }
} else {
return jsgraph()->Int32Constant(0xdeadbeef);
}
} }
private: private:
...@@ -993,16 +996,11 @@ Node* WasmGraphBuilder::Return(unsigned count, Node** vals) { ...@@ -993,16 +996,11 @@ Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
DCHECK_NOT_NULL(*control_); DCHECK_NOT_NULL(*control_);
DCHECK_NOT_NULL(*effect_); DCHECK_NOT_NULL(*effect_);
if (count == 0) {
// Handle a return of void.
vals[0] = jsgraph()->Int32Constant(0);
count = 1;
}
Node** buf = Realloc(vals, count, count + 2); Node** buf = Realloc(vals, count, count + 2);
buf[count] = *effect_; buf[count] = *effect_;
buf[count + 1] = *control_; buf[count + 1] = *control_;
Node* ret = graph()->NewNode(jsgraph()->common()->Return(), count + 2, vals); Node* ret =
graph()->NewNode(jsgraph()->common()->Return(count), count + 2, vals);
MergeControlToEnd(jsgraph(), ret); MergeControlToEnd(jsgraph(), ret);
return ret; return ret;
...@@ -1994,7 +1992,7 @@ Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { ...@@ -1994,7 +1992,7 @@ Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
return call; return call;
} }
Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node** WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
const size_t params = sig->parameter_count(); const size_t params = sig->parameter_count();
const size_t extra = 2; // effect and control inputs. const size_t extra = 2; // effect and control inputs.
...@@ -2014,32 +2012,37 @@ Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args, ...@@ -2014,32 +2012,37 @@ Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
SetSourcePosition(call, position); SetSourcePosition(call, position);
*effect_ = call; *effect_ = call;
return call; size_t ret_count = sig->return_count();
} if (ret_count == 0) return nullptr; // No return value.
Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args,
wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]);
// Add code object as constant.
args[0] = HeapConstant(module_->GetCodeOrPlaceholder(index));
wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
return BuildWasmCall(sig, args, position); Node** rets = Buffer(ret_count);
if (ret_count == 1) {
// Only a single return value.
rets[0] = call;
} else {
// Create projections for all return values.
for (size_t i = 0; i < ret_count; i++) {
rets[i] = graph()->NewNode(jsgraph()->common()->Projection(i), call,
graph()->start());
}
}
return rets;
} }
Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args, Node** WasmGraphBuilder::CallDirect(uint32_t index, Node** args,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]); DCHECK_NULL(args[0]);
// Add code object as constant. // Add code object as constant.
args[0] = HeapConstant(module_->GetImportCode(index)); Handle<Code> code = module_->GetFunctionCode(index);
wasm::FunctionSig* sig = module_->GetImportSignature(index); DCHECK(!code.is_null());
args[0] = HeapConstant(code);
wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
return BuildWasmCall(sig, args, position); return BuildWasmCall(sig, args, position);
} }
Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args, Node** WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
DCHECK_NOT_NULL(args[0]); DCHECK_NOT_NULL(args[0]);
DCHECK(module_ && module_->instance); DCHECK(module_ && module_->instance);
...@@ -2054,6 +2057,7 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args, ...@@ -2054,6 +2057,7 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
// Bounds check the index. // Bounds check the index.
uint32_t table_size = uint32_t table_size =
module_->IsValidTable(0) ? module_->GetTable(0)->max_size : 0; module_->IsValidTable(0) ? module_->GetTable(0)->max_size : 0;
wasm::FunctionSig* sig = module_->GetSignature(index);
if (table_size > 0) { if (table_size > 0) {
// Bounds check against the table size. // Bounds check against the table size.
Node* size = Uint32Constant(table_size); Node* size = Uint32Constant(table_size);
...@@ -2062,7 +2066,11 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args, ...@@ -2062,7 +2066,11 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
} else { } else {
// No function table. Generate a trap and return a constant. // No function table. Generate a trap and return a constant.
trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0), position); trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0), position);
return trap_->GetTrapValue(module_->GetSignature(index)); Node** rets = Buffer(sig->return_count());
for (size_t i = 0; i < sig->return_count(); i++) {
rets[i] = trap_->GetTrapValue(sig->GetReturn(i));
}
return rets;
} }
Node* table = FunctionTable(0); Node* table = FunctionTable(0);
...@@ -2096,7 +2104,6 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args, ...@@ -2096,7 +2104,6 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
*effect_, *control_); *effect_, *control_);
args[0] = load_code; args[0] = load_code;
wasm::FunctionSig* sig = module_->GetSignature(index);
return BuildWasmCall(sig, args, position); return BuildWasmCall(sig, args, position);
} }
...@@ -2693,6 +2700,11 @@ Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { ...@@ -2693,6 +2700,11 @@ Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
} }
} }
Node* WasmGraphBuilder::CurrentMemoryPages() {
return graph()->NewNode(jsgraph()->machine()->Word32Shr(), MemSize(0),
jsgraph()->Int32Constant(16));
}
Node* WasmGraphBuilder::MemSize(uint32_t offset) { Node* WasmGraphBuilder::MemSize(uint32_t offset) {
DCHECK(module_ && module_->instance); DCHECK(module_ && module_->instance);
uint32_t size = static_cast<uint32_t>(module_->instance->mem_size); uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
......
...@@ -153,12 +153,11 @@ class WasmGraphBuilder { ...@@ -153,12 +153,11 @@ class WasmGraphBuilder {
Node* ReturnVoid(); Node* ReturnVoid();
Node* Unreachable(wasm::WasmCodePosition position); Node* Unreachable(wasm::WasmCodePosition position);
Node* CallDirect(uint32_t index, Node** args, Node** CallDirect(uint32_t index, Node** args,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
Node* CallImport(uint32_t index, Node** args, Node** CallIndirect(uint32_t index, Node** args,
wasm::WasmCodePosition position);
Node* CallIndirect(uint32_t index, Node** args,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
void BuildJSToWasmWrapper(Handle<Code> wasm_code, wasm::FunctionSig* sig); void BuildJSToWasmWrapper(Handle<Code> wasm_code, wasm::FunctionSig* sig);
void BuildWasmToJSWrapper(Handle<JSReceiver> target, wasm::FunctionSig* sig); void BuildWasmToJSWrapper(Handle<JSReceiver> target, wasm::FunctionSig* sig);
...@@ -170,7 +169,7 @@ class WasmGraphBuilder { ...@@ -170,7 +169,7 @@ class WasmGraphBuilder {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// Operations that concern the linear memory. // Operations that concern the linear memory.
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
Node* MemSize(uint32_t offset); Node* CurrentMemoryPages();
Node* GetGlobal(uint32_t index); Node* GetGlobal(uint32_t index);
Node* SetGlobal(uint32_t index, Node* val); Node* SetGlobal(uint32_t index, Node* val);
Node* LoadMem(wasm::LocalType type, MachineType memtype, Node* index, Node* LoadMem(wasm::LocalType type, MachineType memtype, Node* index,
...@@ -229,6 +228,7 @@ class WasmGraphBuilder { ...@@ -229,6 +228,7 @@ class WasmGraphBuilder {
Graph* graph(); Graph* graph();
Node* String(const char* string); Node* String(const char* string);
Node* MemSize(uint32_t offset);
Node* MemBuffer(uint32_t offset); Node* MemBuffer(uint32_t offset);
void BoundsCheckMem(MachineType memtype, Node* index, uint32_t offset, void BoundsCheckMem(MachineType memtype, Node* index, uint32_t offset,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
...@@ -240,7 +240,7 @@ class WasmGraphBuilder { ...@@ -240,7 +240,7 @@ class WasmGraphBuilder {
Node* MaskShiftCount64(Node* node); Node* MaskShiftCount64(Node* node);
Node* BuildCCall(MachineSignature* sig, Node** args); Node* BuildCCall(MachineSignature* sig, Node** args);
Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node** BuildWasmCall(wasm::FunctionSig* sig, Node** args,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
Node* BuildF32CopySign(Node* left, Node* right); Node* BuildF32CopySign(Node* left, Node* right);
......
...@@ -532,6 +532,8 @@ DEFINE_BOOL(wasm_simd_prototype, false, ...@@ -532,6 +532,8 @@ DEFINE_BOOL(wasm_simd_prototype, false,
"enable prototype simd opcodes for wasm") "enable prototype simd opcodes for wasm")
DEFINE_BOOL(wasm_eh_prototype, false, DEFINE_BOOL(wasm_eh_prototype, false,
"enable prototype exception handling opcodes for wasm") "enable prototype exception handling opcodes for wasm")
DEFINE_BOOL(wasm_mv_prototype, false,
"enable prototype multi-value support for wasm")
DEFINE_BOOL(wasm_trap_handler, false, DEFINE_BOOL(wasm_trap_handler, false,
"use signal handlers to catch out of bounds memory access in wasm" "use signal handlers to catch out of bounds memory access in wasm"
......
This diff is collapsed.
...@@ -22,6 +22,7 @@ class WasmGraphBuilder; ...@@ -22,6 +22,7 @@ class WasmGraphBuilder;
namespace wasm { namespace wasm {
const uint32_t kMaxNumWasmLocals = 8000000; const uint32_t kMaxNumWasmLocals = 8000000;
struct WasmGlobal;
// Helpers for decoding different kinds of operands which follow bytecodes. // Helpers for decoding different kinds of operands which follow bytecodes.
struct LocalIndexOperand { struct LocalIndexOperand {
...@@ -81,39 +82,111 @@ struct ImmF64Operand { ...@@ -81,39 +82,111 @@ struct ImmF64Operand {
struct GlobalIndexOperand { struct GlobalIndexOperand {
uint32_t index; uint32_t index;
LocalType type; LocalType type;
const WasmGlobal* global;
unsigned length; unsigned length;
inline GlobalIndexOperand(Decoder* decoder, const byte* pc) { inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
index = decoder->checked_read_u32v(pc, 1, &length, "global index"); index = decoder->checked_read_u32v(pc, 1, &length, "global index");
global = nullptr;
type = kAstStmt; type = kAstStmt;
} }
}; };
struct BlockTypeOperand {
uint32_t arity;
const byte* types; // pointer to encoded types for the block.
unsigned length;
inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
uint8_t val = decoder->checked_read_u8(pc, 1, "block type");
LocalType type = kAstStmt;
length = 1;
arity = 0;
types = nullptr;
if (decode_local_type(val, &type)) {
arity = type == kAstStmt ? 0 : 1;
types = pc + 1;
} else {
// Handle multi-value blocks.
if (!FLAG_wasm_mv_prototype) {
decoder->error(pc, pc + 1, "invalid block arity > 1");
return;
}
if (val != kMultivalBlock) {
decoder->error(pc, pc + 1, "invalid block type");
return;
}
// Decode and check the types vector of the block.
unsigned len = 0;
uint32_t count = decoder->checked_read_u32v(pc, 2, &len, "block arity");
// {count} is encoded as {arity-2}, so that a {0} count here corresponds
// to a block with 2 values. This makes invalid/redundant encodings
// impossible.
arity = count + 2;
length = 1 + len + arity;
types = pc + 1 + 1 + len;
for (uint32_t i = 0; i < arity; i++) {
uint32_t offset = 1 + 1 + len + i;
val = decoder->checked_read_u8(pc, offset, "block type");
decode_local_type(val, &type);
if (type == kAstStmt) {
decoder->error(pc, pc + offset, "invalid block type");
return;
}
}
}
}
// Decode a byte representing a local type. Return {false} if the encoded
// byte was invalid or {kMultivalBlock}.
bool decode_local_type(uint8_t val, LocalType* result) {
switch (static_cast<LocalTypeCode>(val)) {
case kLocalVoid:
*result = kAstStmt;
return true;
case kLocalI32:
*result = kAstI32;
return true;
case kLocalI64:
*result = kAstI64;
return true;
case kLocalF32:
*result = kAstF32;
return true;
case kLocalF64:
*result = kAstF64;
return true;
default:
*result = kAstStmt;
return false;
}
}
LocalType read_entry(unsigned index) {
DCHECK_LT(index, arity);
LocalType result;
CHECK(decode_local_type(types[index], &result));
return result;
}
};
struct Control; struct Control;
struct BreakDepthOperand { struct BreakDepthOperand {
uint32_t arity;
uint32_t depth; uint32_t depth;
Control* target; Control* target;
unsigned length; unsigned length;
inline BreakDepthOperand(Decoder* decoder, const byte* pc) { inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
unsigned len1 = 0; depth = decoder->checked_read_u32v(pc, 1, &length, "break depth");
unsigned len2 = 0;
arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
depth = decoder->checked_read_u32v(pc, 1 + len1, &len2, "break depth");
length = len1 + len2;
target = nullptr; target = nullptr;
} }
}; };
struct CallIndirectOperand { struct CallIndirectOperand {
uint32_t arity;
uint32_t index; uint32_t index;
FunctionSig* sig; FunctionSig* sig;
unsigned length; unsigned length;
inline CallIndirectOperand(Decoder* decoder, const byte* pc) { inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
unsigned len1 = 0; unsigned len1 = 0;
unsigned len2 = 0; unsigned len2 = 0;
arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "signature index"); index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "signature index");
length = len1 + len2; length = len1 + len2;
sig = nullptr; sig = nullptr;
...@@ -121,59 +194,32 @@ struct CallIndirectOperand { ...@@ -121,59 +194,32 @@ struct CallIndirectOperand {
}; };
struct CallFunctionOperand { struct CallFunctionOperand {
uint32_t arity;
uint32_t index; uint32_t index;
FunctionSig* sig; FunctionSig* sig;
unsigned length; unsigned length;
inline CallFunctionOperand(Decoder* decoder, const byte* pc) { inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
unsigned len1 = 0; unsigned len1 = 0;
unsigned len2 = 0; unsigned len2 = 0;
arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index"); index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index");
length = len1 + len2; length = len1 + len2;
sig = nullptr; sig = nullptr;
} }
}; };
struct CallImportOperand {
uint32_t arity;
uint32_t index;
FunctionSig* sig;
unsigned length;
inline CallImportOperand(Decoder* decoder, const byte* pc) {
unsigned len1 = 0;
unsigned len2 = 0;
arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "import index");
length = len1 + len2;
sig = nullptr;
}
};
struct BranchTableOperand { struct BranchTableOperand {
uint32_t arity;
uint32_t table_count; uint32_t table_count;
const byte* start;
const byte* table; const byte* table;
unsigned length;
inline BranchTableOperand(Decoder* decoder, const byte* pc) { inline BranchTableOperand(Decoder* decoder, const byte* pc) {
DCHECK_EQ(kExprBrTable, decoder->checked_read_u8(pc, 0, "opcode"));
start = pc + 1;
unsigned len1 = 0; unsigned len1 = 0;
unsigned len2 = 0; table_count = decoder->checked_read_u32v(pc, 1, &len1, "table count");
arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count");
table_count =
decoder->checked_read_u32v(pc, 1 + len1, &len2, "table count");
if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 || if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 ||
len1 + len2 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) { len1 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
decoder->error(pc, "branch table size overflow"); decoder->error(pc, "branch table size overflow");
} }
length = len1 + len2 + (table_count + 1) * sizeof(uint32_t); table = pc + 1 + len1;
uint32_t table_start = 1 + len1 + len2;
if (decoder->check(pc, table_start, (table_count + 1) * sizeof(uint32_t),
"expected <table entries>")) {
table = pc + table_start;
} else {
table = nullptr;
}
} }
inline uint32_t read_entry(Decoder* decoder, unsigned i) { inline uint32_t read_entry(Decoder* decoder, unsigned i) {
DCHECK(i <= table_count); DCHECK(i <= table_count);
...@@ -181,6 +227,43 @@ struct BranchTableOperand { ...@@ -181,6 +227,43 @@ struct BranchTableOperand {
} }
}; };
// A helper to iterate over a branch table.
class BranchTableIterator {
public:
unsigned cur_index() { return index_; }
bool has_next() { return index_ <= table_count_; }
uint32_t next() {
DCHECK(has_next());
index_++;
unsigned length = 0;
uint32_t result =
decoder_->checked_read_u32v(pc_, 0, &length, "branch table entry");
pc_ += length;
return result;
}
// length, including the length of the {BranchTableOperand}, but not the
// opcode.
unsigned length() {
while (has_next()) next();
return static_cast<unsigned>(pc_ - start_);
}
const byte* pc() { return pc_; }
BranchTableIterator(Decoder* decoder, BranchTableOperand& operand)
: decoder_(decoder),
start_(operand.start),
pc_(operand.table),
index_(0),
table_count_(operand.table_count) {}
private:
Decoder* decoder_;
const byte* start_;
const byte* pc_;
uint32_t index_; // the current index.
uint32_t table_count_; // the count of entries, not including default.
};
struct MemoryAccessOperand { struct MemoryAccessOperand {
uint32_t alignment; uint32_t alignment;
uint32_t offset; uint32_t offset;
...@@ -203,15 +286,6 @@ struct MemoryAccessOperand { ...@@ -203,15 +286,6 @@ struct MemoryAccessOperand {
} }
}; };
struct ReturnArityOperand {
uint32_t arity;
unsigned length;
inline ReturnArityOperand(Decoder* decoder, const byte* pc) {
arity = decoder->checked_read_u32v(pc, 1, &length, "return count");
}
};
typedef compiler::WasmGraphBuilder TFBuilder; typedef compiler::WasmGraphBuilder TFBuilder;
struct ModuleEnv; // forward declaration of module interface. struct ModuleEnv; // forward declaration of module interface.
...@@ -284,9 +358,6 @@ BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, ...@@ -284,9 +358,6 @@ BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals,
// Computes the length of the opcode at the given address. // Computes the length of the opcode at the given address.
unsigned OpcodeLength(const byte* pc, const byte* end); unsigned OpcodeLength(const byte* pc, const byte* end);
// Computes the arity (number of sub-nodes) of the opcode at the given address.
unsigned OpcodeArity(const byte* pc, const byte* end);
// A simple forward iterator for bytecodes. // A simple forward iterator for bytecodes.
class BytecodeIterator : public Decoder { class BytecodeIterator : public Decoder {
public: public:
......
...@@ -208,6 +208,19 @@ class Decoder { ...@@ -208,6 +208,19 @@ class Decoder {
// Consume {size} bytes and send them to the bit bucket, advancing {pc_}. // Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
void consume_bytes(int size) { void consume_bytes(int size) {
TRACE(" +%d %-20s: %d bytes\n", static_cast<int>(pc_ - start_), "skip",
size);
if (checkAvailable(size)) {
pc_ += size;
} else {
pc_ = limit_;
}
}
// Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
void consume_bytes(uint32_t size, const char* name = "skip") {
TRACE(" +%d %-20s: %d bytes\n", static_cast<int>(pc_ - start_), name,
size);
if (checkAvailable(size)) { if (checkAvailable(size)) {
pc_ += size; pc_ += size;
} else { } else {
......
This diff is collapsed.
...@@ -121,19 +121,22 @@ class WasmFunctionBuilder : public ZoneObject { ...@@ -121,19 +121,22 @@ class WasmFunctionBuilder : public ZoneObject {
void Emit(WasmOpcode opcode); void Emit(WasmOpcode opcode);
void EmitGetLocal(uint32_t index); void EmitGetLocal(uint32_t index);
void EmitSetLocal(uint32_t index); void EmitSetLocal(uint32_t index);
void EmitTeeLocal(uint32_t index);
void EmitI32Const(int32_t val); void EmitI32Const(int32_t val);
void EmitWithU8(WasmOpcode opcode, const byte immediate); void EmitWithU8(WasmOpcode opcode, const byte immediate);
void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2); void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2);
void EmitWithVarInt(WasmOpcode opcode, uint32_t immediate); void EmitWithVarInt(WasmOpcode opcode, uint32_t immediate);
void SetExported(); void SetExported();
void SetName(const char* name, int name_length); void SetName(const char* name, int name_length);
bool exported() { return exported_; }
// Writing methods.
void WriteSignature(ZoneBuffer& buffer) const; void WriteSignature(ZoneBuffer& buffer) const;
void WriteExport(ZoneBuffer& buffer, uint32_t func_index) const; void WriteExport(ZoneBuffer& buffer) const;
void WriteBody(ZoneBuffer& buffer) const; void WriteBody(ZoneBuffer& buffer) const;
bool exported() { return exported_; }
uint32_t func_index() { return func_index_; }
FunctionSig* signature();
private: private:
explicit WasmFunctionBuilder(WasmModuleBuilder* builder); explicit WasmFunctionBuilder(WasmModuleBuilder* builder);
friend class WasmModuleBuilder; friend class WasmModuleBuilder;
...@@ -142,6 +145,7 @@ class WasmFunctionBuilder : public ZoneObject { ...@@ -142,6 +145,7 @@ class WasmFunctionBuilder : public ZoneObject {
LocalDeclEncoder locals_; LocalDeclEncoder locals_;
uint32_t signature_index_; uint32_t signature_index_;
bool exported_; bool exported_;
uint32_t func_index_;
ZoneVector<uint8_t> body_; ZoneVector<uint8_t> body_;
ZoneVector<char> name_; ZoneVector<char> name_;
ZoneVector<uint32_t> i32_temps_; ZoneVector<uint32_t> i32_temps_;
...@@ -212,14 +216,17 @@ class WasmModuleBuilder : public ZoneObject { ...@@ -212,14 +216,17 @@ class WasmModuleBuilder : public ZoneObject {
explicit WasmModuleBuilder(Zone* zone); explicit WasmModuleBuilder(Zone* zone);
// Building methods. // Building methods.
uint32_t AddFunction(); uint32_t AddImport(const char* name, int name_length, FunctionSig* sig);
uint32_t AddGlobal(LocalType type, bool exported); void SetImportName(uint32_t index, const char* name, int name_length) {
WasmFunctionBuilder* FunctionAt(size_t index); imports_[index].name = name;
imports_[index].name_length = name_length;
}
WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr);
uint32_t AddGlobal(LocalType type, bool exported, bool mutability = true);
void AddDataSegment(WasmDataSegmentEncoder* data); void AddDataSegment(WasmDataSegmentEncoder* data);
uint32_t AddSignature(FunctionSig* sig); uint32_t AddSignature(FunctionSig* sig);
void AddIndirectFunction(uint32_t index); void AddIndirectFunction(uint32_t index);
void MarkStartFunction(uint32_t index); void MarkStartFunction(WasmFunctionBuilder* builder);
uint32_t AddImport(const char* name, int name_length, FunctionSig* sig);
// Writing methods. // Writing methods.
void WriteTo(ZoneBuffer& buffer) const; void WriteTo(ZoneBuffer& buffer) const;
...@@ -231,18 +238,25 @@ class WasmModuleBuilder : public ZoneObject { ...@@ -231,18 +238,25 @@ class WasmModuleBuilder : public ZoneObject {
Zone* zone() { return zone_; } Zone* zone() { return zone_; }
FunctionSig* GetSignature(uint32_t index) { return signatures_[index]; }
private: private:
friend class WasmFunctionBuilder;
Zone* zone_; Zone* zone_;
ZoneVector<FunctionSig*> signatures_; ZoneVector<FunctionSig*> signatures_;
ZoneVector<WasmFunctionImport> imports_; ZoneVector<WasmFunctionImport> imports_;
ZoneVector<WasmFunctionBuilder*> functions_; ZoneVector<WasmFunctionBuilder*> functions_;
ZoneVector<WasmDataSegmentEncoder*> data_segments_; ZoneVector<WasmDataSegmentEncoder*> data_segments_;
ZoneVector<uint32_t> indirect_functions_; ZoneVector<uint32_t> indirect_functions_;
ZoneVector<std::pair<LocalType, bool>> globals_; ZoneVector<std::tuple<LocalType, bool, bool>> globals_;
SignatureMap signature_map_; SignatureMap signature_map_;
int start_function_index_; int start_function_index_;
}; };
inline FunctionSig* WasmFunctionBuilder::signature() {
return builder_->signatures_[signature_index_];
}
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
This diff is collapsed.
...@@ -30,8 +30,11 @@ FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone, ModuleEnv* env, ...@@ -30,8 +30,11 @@ FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone, ModuleEnv* env,
// Extracts the function offset table from the wasm module bytes. // Extracts the function offset table from the wasm module bytes.
// Returns a vector with <offset, length> entries, or failure if the wasm bytes // Returns a vector with <offset, length> entries, or failure if the wasm bytes
// are detected as invalid. Note that this validation is not complete. // are detected as invalid. Note that this validation is not complete.
FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start, FunctionOffsetsResult DecodeWasmFunctionOffsets(
const byte* module_end); const byte* module_start, const byte* module_end,
uint32_t num_imported_functions);
WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end);
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
...@@ -32,11 +32,15 @@ ByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) { ...@@ -32,11 +32,15 @@ ByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) {
FunctionOffsetsResult function_offsets; FunctionOffsetsResult function_offsets;
{ {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Handle<JSObject> wasm_object(debug_info->wasm_object(), isolate);
uint32_t num_imported_functions =
wasm::GetNumImportedFunctions(wasm_object);
SeqOneByteString *wasm_bytes = SeqOneByteString *wasm_bytes =
wasm::GetWasmBytes(debug_info->wasm_object()); wasm::GetWasmBytes(debug_info->wasm_object());
const byte *bytes_start = wasm_bytes->GetChars(); const byte *bytes_start = wasm_bytes->GetChars();
const byte *bytes_end = bytes_start + wasm_bytes->length(); const byte *bytes_end = bytes_start + wasm_bytes->length();
function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end); function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end,
num_imported_functions);
} }
DCHECK(function_offsets.ok()); DCHECK(function_offsets.ok());
size_t array_size = 2 * kIntSize * function_offsets.val.size(); size_t array_size = 2 * kIntSize * function_offsets.val.size();
......
This diff is collapsed.
...@@ -28,15 +28,7 @@ typedef uint32_t spdiff_t; ...@@ -28,15 +28,7 @@ typedef uint32_t spdiff_t;
const pc_t kInvalidPc = 0x80000000; const pc_t kInvalidPc = 0x80000000;
// Visible for testing. A {ControlTransfer} helps the interpreter figure out typedef ZoneMap<pc_t, pcdiff_t> ControlTransferMap;
// the target program counter and stack manipulations for a branch.
struct ControlTransfer {
enum StackAction { kNoAction, kPopAndRepush, kPushVoid };
pcdiff_t pcdiff; // adjustment to the program counter (positive or negative).
spdiff_t spdiff; // number of elements to pop off the stack.
StackAction action; // action to perform on the stack.
};
typedef ZoneMap<pc_t, ControlTransfer> ControlTransferMap;
// Macro for defining union members. // Macro for defining union members.
#define FOREACH_UNION_MEMBER(V) \ #define FOREACH_UNION_MEMBER(V) \
...@@ -132,7 +124,7 @@ class WasmInterpreter { ...@@ -132,7 +124,7 @@ class WasmInterpreter {
virtual int GetFrameCount() = 0; virtual int GetFrameCount() = 0;
virtual const WasmFrame* GetFrame(int index) = 0; virtual const WasmFrame* GetFrame(int index) = 0;
virtual WasmFrame* GetMutableFrame(int index) = 0; virtual WasmFrame* GetMutableFrame(int index) = 0;
virtual WasmVal GetReturnValue() = 0; virtual WasmVal GetReturnValue(int index = 0) = 0;
// Thread-specific breakpoints. // Thread-specific breakpoints.
bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled); bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
...@@ -189,9 +181,8 @@ class WasmInterpreter { ...@@ -189,9 +181,8 @@ class WasmInterpreter {
bool SetFunctionCodeForTesting(const WasmFunction* function, bool SetFunctionCodeForTesting(const WasmFunction* function,
const byte* start, const byte* end); const byte* start, const byte* end);
// Computes the control targets for the given bytecode as {pc offset, sp // Computes the control transfers for the given bytecode. Used internally in
// offset} // the interpreter, but exposed for testing.
// pairs. Used internally in the interpreter, but exposed for testing.
static ControlTransferMap ComputeControlTransfersForTesting(Zone* zone, static ControlTransferMap ComputeControlTransfersForTesting(Zone* zone,
const byte* start, const byte* start,
const byte* end); const byte* end);
......
...@@ -160,7 +160,7 @@ i::MaybeHandle<i::JSObject> InstantiateModule( ...@@ -160,7 +160,7 @@ i::MaybeHandle<i::JSObject> InstantiateModule(
} }
object = i::wasm::WasmModule::Instantiate( object = i::wasm::WasmModule::Instantiate(
isolate, module_object.ToHandleChecked(), ffi, memory); isolate, thrower, module_object.ToHandleChecked(), ffi, memory);
if (!object.is_null()) { if (!object.is_null()) {
args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked())); args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
} }
...@@ -296,10 +296,10 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -296,10 +296,10 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj); i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj);
memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj)); memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj));
} }
i::MaybeHandle<i::JSObject> instance = i::MaybeHandle<i::JSObject> instance = i::wasm::WasmModule::Instantiate(
i::wasm::WasmModule::Instantiate(i_isolate, module_obj, ffi, memory); i_isolate, &thrower, module_obj, ffi, memory);
if (instance.is_null()) { if (instance.is_null()) {
thrower.Error("Could not instantiate module"); if (!thrower.error()) thrower.Error("Could not instantiate module");
return; return;
} }
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
...@@ -388,10 +388,10 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -388,10 +388,10 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::JSFunction> table_cons( i::Handle<i::JSFunction> table_ctor(
i_isolate->native_context()->wasm_table_constructor()); i_isolate->native_context()->wasm_table_constructor());
i::Handle<i::JSObject> table_obj = i::Handle<i::JSObject> table_obj =
i_isolate->factory()->NewJSObject(table_cons); i_isolate->factory()->NewJSObject(table_ctor);
i::Handle<i::FixedArray> fixed_array = i::Handle<i::FixedArray> fixed_array =
i_isolate->factory()->NewFixedArray(initial); i_isolate->factory()->NewFixedArray(initial);
i::Object* null = i_isolate->heap()->null_value(); i::Object* null = i_isolate->heap()->null_value();
...@@ -406,6 +406,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -406,6 +406,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(table_obj)); return_value.Set(Utils::ToLocal(table_obj));
} }
void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) { void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate(); v8::Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -436,23 +437,14 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -436,23 +437,14 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
} }
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::JSFunction> memory_cons(
i_isolate->native_context()->wasm_memory_constructor());
i::Handle<i::JSObject> memory_obj =
i_isolate->factory()->NewJSObject(memory_cons);
i::Handle<i::JSArrayBuffer> buffer = i::Handle<i::JSArrayBuffer> buffer =
i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared); i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared);
size_t size = static_cast<size_t>(i::wasm::WasmModule::kPageSize) * size_t size = static_cast<size_t>(i::wasm::WasmModule::kPageSize) *
static_cast<size_t>(initial); static_cast<size_t>(initial);
i::JSArrayBuffer::SetupAllocatingData(buffer, i_isolate, size); i::JSArrayBuffer::SetupAllocatingData(buffer, i_isolate, size);
memory_obj->SetInternalField(0, *buffer);
memory_obj->SetInternalField( i::Handle<i::JSObject> memory_obj = i::WasmJs::CreateWasmMemoryObject(
1, has_maximum i_isolate, buffer, has_maximum, maximum);
? static_cast<i::Object*>(i::Smi::FromInt(maximum))
: static_cast<i::Object*>(i_isolate->heap()->undefined_value()));
i::Handle<i::Symbol> memory_sym(
i_isolate->native_context()->wasm_memory_sym());
i::Object::SetProperty(memory_obj, memory_sym, memory_obj, i::STRICT).Check();
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(memory_obj)); return_value.Set(Utils::ToLocal(memory_obj));
} }
...@@ -492,6 +484,24 @@ void WebAssemblyMemoryGetBuffer( ...@@ -492,6 +484,24 @@ void WebAssemblyMemoryGetBuffer(
} }
} // namespace } // namespace
i::Handle<i::JSObject> i::WasmJs::CreateWasmMemoryObject(
i::Isolate* i_isolate, i::Handle<i::JSArrayBuffer> buffer, bool has_maximum,
int maximum) {
i::Handle<i::JSFunction> memory_ctor(
i_isolate->native_context()->wasm_memory_constructor());
i::Handle<i::JSObject> memory_obj =
i_isolate->factory()->NewJSObject(memory_ctor);
memory_obj->SetInternalField(0, *buffer);
memory_obj->SetInternalField(
1, has_maximum
? static_cast<i::Object*>(i::Smi::FromInt(maximum))
: static_cast<i::Object*>(i_isolate->heap()->undefined_value()));
i::Handle<i::Symbol> memory_sym(
i_isolate->native_context()->wasm_memory_sym());
i::Object::SetProperty(memory_obj, memory_sym, memory_obj, i::STRICT).Check();
return memory_obj;
}
// TODO(titzer): we use the API to create the function template because the // TODO(titzer): we use the API to create the function template because the
// internal guts are too ugly to replicate here. // internal guts are too ugly to replicate here.
static i::Handle<i::FunctionTemplateInfo> NewTemplate(i::Isolate* i_isolate, static i::Handle<i::FunctionTemplateInfo> NewTemplate(i::Isolate* i_isolate,
......
...@@ -24,6 +24,10 @@ class WasmJs { ...@@ -24,6 +24,10 @@ class WasmJs {
static void InstallWasmConstructors(Isolate* isolate, static void InstallWasmConstructors(Isolate* isolate,
Handle<JSGlobalObject> global, Handle<JSGlobalObject> global,
Handle<Context> context); Handle<Context> context);
static Handle<JSObject> CreateWasmMemoryObject(Isolate* isolate,
Handle<JSArrayBuffer> buffer,
bool has_maximum, int maximum);
}; };
} // namespace internal } // namespace internal
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -22,6 +22,9 @@ enum LocalTypeCode { ...@@ -22,6 +22,9 @@ enum LocalTypeCode {
kLocalS128 = 5 kLocalS128 = 5
}; };
// Type code for multi-value block types.
static const uint8_t kMultivalBlock = 0x41;
// We reuse the internal machine type to represent WebAssembly AST types. // We reuse the internal machine type to represent WebAssembly AST types.
// A typedef improves readability without adding a whole new type system. // A typedef improves readability without adding a whole new type system.
typedef MachineRepresentation LocalType; typedef MachineRepresentation LocalType;
...@@ -44,7 +47,7 @@ const WasmCodePosition kNoCodePosition = -1; ...@@ -44,7 +47,7 @@ const WasmCodePosition kNoCodePosition = -1;
// Control expressions and blocks. // Control expressions and blocks.
#define FOREACH_CONTROL_OPCODE(V) \ #define FOREACH_CONTROL_OPCODE(V) \
V(Nop, 0x00, _) \ V(Unreachable, 0x00, _) \
V(Block, 0x01, _) \ V(Block, 0x01, _) \
V(Loop, 0x02, _) \ V(Loop, 0x02, _) \
V(If, 0x03, _) \ V(If, 0x03, _) \
...@@ -54,7 +57,7 @@ const WasmCodePosition kNoCodePosition = -1; ...@@ -54,7 +57,7 @@ const WasmCodePosition kNoCodePosition = -1;
V(BrIf, 0x07, _) \ V(BrIf, 0x07, _) \
V(BrTable, 0x08, _) \ V(BrTable, 0x08, _) \
V(Return, 0x09, _) \ V(Return, 0x09, _) \
V(Unreachable, 0x0a, _) \ V(Nop, 0x0a, _) \
V(Throw, 0xfa, _) \ V(Throw, 0xfa, _) \
V(Try, 0xfb, _) \ V(Try, 0xfb, _) \
V(Catch, 0xfe, _) \ V(Catch, 0xfe, _) \
...@@ -68,9 +71,10 @@ const WasmCodePosition kNoCodePosition = -1; ...@@ -68,9 +71,10 @@ const WasmCodePosition kNoCodePosition = -1;
V(F32Const, 0x13, _) \ V(F32Const, 0x13, _) \
V(GetLocal, 0x14, _) \ V(GetLocal, 0x14, _) \
V(SetLocal, 0x15, _) \ V(SetLocal, 0x15, _) \
V(TeeLocal, 0x19, _) \
V(Drop, 0x0b, _) \
V(CallFunction, 0x16, _) \ V(CallFunction, 0x16, _) \
V(CallIndirect, 0x17, _) \ V(CallIndirect, 0x17, _) \
V(CallImport, 0x18, _) \
V(I8Const, 0xcb, _) \ V(I8Const, 0xcb, _) \
V(GetGlobal, 0xbb, _) \ V(GetGlobal, 0xbb, _) \
V(SetGlobal, 0xbc, _) V(SetGlobal, 0xbc, _)
...@@ -497,6 +501,8 @@ class WasmOpcodes { ...@@ -497,6 +501,8 @@ class WasmOpcodes {
return 1 << ElementSizeLog2Of(type.representation()); return 1 << ElementSizeLog2Of(type.representation());
} }
static byte MemSize(LocalType type) { return 1 << ElementSizeLog2Of(type); }
static LocalTypeCode LocalTypeCodeFor(LocalType type) { static LocalTypeCode LocalTypeCodeFor(LocalType type) {
switch (type) { switch (type) {
case kAstI32: case kAstI32:
......
...@@ -22,19 +22,7 @@ namespace wasm { ...@@ -22,19 +22,7 @@ namespace wasm {
// Error codes for programmatic checking of the decoder's verification. // Error codes for programmatic checking of the decoder's verification.
enum ErrorCode { enum ErrorCode {
kSuccess, kSuccess,
kError, // TODO(titzer): remove me kError, // TODO(titzer): introduce real error codes
kOutOfMemory, // decoder ran out of memory
kEndOfCode, // end of code reached prematurely
kInvalidOpcode, // found invalid opcode
kUnreachableCode, // found unreachable code
kImproperContinue, // improperly nested continue
kImproperBreak, // improperly nested break
kReturnCount, // return count mismatch
kTypeError, // type mismatch
kInvalidLocalIndex, // invalid local
kInvalidGlobalIndex, // invalid global
kInvalidFunctionIndex, // invalid function
kInvalidMemType // invalid memory type
}; };
// The overall result of decoding a function or a module. // The overall result of decoding a function or a module.
......
This diff is collapsed.
...@@ -152,7 +152,7 @@ TEST(Run_CallJS_Add_jswrapped) { ...@@ -152,7 +152,7 @@ TEST(Run_CallJS_Add_jswrapped) {
WasmFunctionCompiler t(sigs.i_i(), &module); WasmFunctionCompiler t(sigs.i_i(), &module);
uint32_t js_index = uint32_t js_index =
module.AddJsFunction(sigs.i_i(), "(function(a) { return a + 99; })"); module.AddJsFunction(sigs.i_i(), "(function(a) { return a + 99; })");
BUILD(t, WASM_CALL_FUNCTION1(js_index, WASM_GET_LOCAL(0))); BUILD(t, WASM_CALL_FUNCTION(js_index, WASM_GET_LOCAL(0)));
Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd()); Handle<JSFunction> jsfunc = module.WrapCode(t.CompileAndAdd());
...@@ -182,8 +182,7 @@ void RunJSSelectTest(int which) { ...@@ -182,8 +182,7 @@ void RunJSSelectTest(int which) {
ADD_CODE(code, WASM_F64(inputs.arg_d(i))); ADD_CODE(code, WASM_F64(inputs.arg_d(i)));
} }
ADD_CODE(code, kExprCallFunction, static_cast<byte>(num_params), ADD_CODE(code, kExprCallFunction, static_cast<byte>(js_index));
static_cast<byte>(js_index));
size_t end = code.size(); size_t end = code.size();
code.push_back(0); code.push_back(0);
...@@ -420,7 +419,7 @@ void RunJSSelectAlignTest(int num_args, int num_params) { ...@@ -420,7 +419,7 @@ void RunJSSelectAlignTest(int num_args, int num_params) {
ADD_CODE(code, WASM_GET_LOCAL(i)); ADD_CODE(code, WASM_GET_LOCAL(i));
} }
ADD_CODE(code, kExprCallFunction, static_cast<byte>(num_params), 0); ADD_CODE(code, kExprCallFunction, 0);
size_t end = code.size(); size_t end = code.size();
code.push_back(0); code.push_back(0);
......
This diff is collapsed.
This diff is collapsed.
...@@ -41,9 +41,9 @@ void testFunctionNameTable(Vector<Vector<const char>> names) { ...@@ -41,9 +41,9 @@ void testFunctionNameTable(Vector<Vector<const char>> names) {
name.start() + name.length()); name.start() + name.length());
// Make every second function name null-terminated. // Make every second function name null-terminated.
if (func_index % 2) all_names.push_back('\0'); if (func_index % 2) all_names.push_back('\0');
module.functions.push_back({nullptr, 0, 0, module.functions.push_back(
static_cast<uint32_t>(name_offset), {nullptr, 0, 0, static_cast<uint32_t>(name_offset),
static_cast<uint32_t>(name.length()), 0, 0}); static_cast<uint32_t>(name.length()), 0, 0, false, false});
++func_index; ++func_index;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment