summaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm
diff options
context:
space:
mode:
authorAli Ijaz Sheikh <ofrobots@google.com>2016-04-07 14:06:55 -0700
committerAli Ijaz Sheikh <ofrobots@google.com>2016-04-14 10:03:39 -0700
commit52af5c4eebf4de8638aef0338bd826656312a02a (patch)
tree628dc9fb0b558c3a73a2160706fef368876fe548 /deps/v8/src/wasm
parent6e3e8acc7cc7ebd3d67db5ade1247b8b558efe09 (diff)
downloadnode-new-52af5c4eebf4de8638aef0338bd826656312a02a.tar.gz
deps: upgrade V8 to 5.0.71.32
* Pick up the branch head for V8 5.0 stable [1] * Edit v8 gitignore to allow trace_event copy * Update V8 DEP trace_event as per deps/v8/DEPS [2] [1] https://chromium.googlesource.com/v8/v8.git/+/3c67831 [2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/4b09207e447ae5bd34643b4c6321bee7b76d35f9 Ref: https://github.com/nodejs/node/pull/5945 PR-URL: https://github.com/nodejs/node/pull/6111 Reviewed-By: targos - Michaƫl Zasso <mic.besace@gmail.com> Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Diffstat (limited to 'deps/v8/src/wasm')
-rw-r--r--deps/v8/src/wasm/asm-wasm-builder.cc440
-rw-r--r--deps/v8/src/wasm/asm-wasm-builder.h5
-rw-r--r--deps/v8/src/wasm/ast-decoder.cc979
-rw-r--r--deps/v8/src/wasm/ast-decoder.h213
-rw-r--r--deps/v8/src/wasm/decoder.h213
-rw-r--r--deps/v8/src/wasm/encoder.cc82
-rw-r--r--deps/v8/src/wasm/encoder.h19
-rw-r--r--deps/v8/src/wasm/module-decoder.cc195
-rw-r--r--deps/v8/src/wasm/wasm-js.cc172
-rw-r--r--deps/v8/src/wasm/wasm-macro-gen.h9
-rw-r--r--deps/v8/src/wasm/wasm-module.cc420
-rw-r--r--deps/v8/src/wasm/wasm-module.h95
-rw-r--r--deps/v8/src/wasm/wasm-opcodes.cc14
-rw-r--r--deps/v8/src/wasm/wasm-opcodes.h8
14 files changed, 1845 insertions, 1019 deletions
diff --git a/deps/v8/src/wasm/asm-wasm-builder.cc b/deps/v8/src/wasm/asm-wasm-builder.cc
index 30f84642f8..ee5427b174 100644
--- a/deps/v8/src/wasm/asm-wasm-builder.cc
+++ b/deps/v8/src/wasm/asm-wasm-builder.cc
@@ -27,7 +27,8 @@ namespace wasm {
class AsmWasmBuilderImpl : public AstVisitor {
public:
- AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal)
+ AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
+ Handle<Object> foreign)
: local_variables_(HashMap::PointersMatch,
ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)),
@@ -44,17 +45,23 @@ class AsmWasmBuilderImpl : public AstVisitor {
literal_(literal),
isolate_(isolate),
zone_(zone),
+ foreign_(foreign),
cache_(TypeCache::Get()),
breakable_blocks_(zone),
block_size_(0),
- init_function_index(0) {
+ init_function_index_(0),
+ next_table_index_(0),
+ function_tables_(HashMap::PointersMatch,
+ ZoneHashMap::kDefaultHashMapCapacity,
+ ZoneAllocationPolicy(zone)),
+ imported_function_table_(this) {
InitializeAstVisitor(isolate);
}
void InitializeInitFunction() {
unsigned char init[] = "__init__";
- init_function_index = builder_->AddFunction();
- current_function_builder_ = builder_->FunctionAt(init_function_index);
+ init_function_index_ = builder_->AddFunction();
+ current_function_builder_ = builder_->FunctionAt(init_function_index_);
current_function_builder_->SetName(init, 8);
current_function_builder_->ReturnType(kAstStmt);
current_function_builder_->Exported(1);
@@ -70,7 +77,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitFunctionDeclaration(FunctionDeclaration* decl) {
DCHECK(!in_function_);
- DCHECK(current_function_builder_ == nullptr);
+ DCHECK_NULL(current_function_builder_);
uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
current_function_builder_ = builder_->FunctionAt(index);
in_function_ = true;
@@ -103,11 +110,15 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
}
}
- DCHECK(in_function_);
- BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
- static_cast<byte>(stmt->statements()->length()));
- RECURSE(VisitStatements(stmt->statements()));
- DCHECK(block_size_ >= 0);
+ if (in_function_) {
+ BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
+ false,
+ static_cast<byte>(stmt->statements()->length()));
+ RECURSE(VisitStatements(stmt->statements()));
+ DCHECK(block_size_ >= 0);
+ } else {
+ RECURSE(VisitStatements(stmt->statements()));
+ }
}
class BlockVisitor {
@@ -162,7 +173,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitContinueStatement(ContinueStatement* stmt) {
DCHECK(in_function_);
- DCHECK(stmt->target() != NULL);
+ DCHECK_NOT_NULL(stmt->target());
int i = static_cast<int>(breakable_blocks_.size()) - 1;
int block_distance = 0;
for (; i >= 0; i--) {
@@ -183,7 +194,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitBreakStatement(BreakStatement* stmt) {
DCHECK(in_function_);
- DCHECK(stmt->target() != NULL);
+ DCHECK_NOT_NULL(stmt->target());
int i = static_cast<int>(breakable_blocks_.size()) - 1;
int block_distance = 0;
for (; i >= 0; i--) {
@@ -229,7 +240,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void CompileCase(CaseClause* clause, uint16_t fall_through,
VariableProxy* tag) {
Literal* label = clause->label()->AsLiteral();
- DCHECK(label != nullptr);
+ DCHECK_NOT_NULL(label);
block_size_++;
current_function_builder_->Emit(kExprIf);
current_function_builder_->Emit(kExprI32Ior);
@@ -247,7 +258,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitSwitchStatement(SwitchStatement* stmt) {
VariableProxy* tag = stmt->tag()->AsVariableProxy();
- DCHECK(tag != NULL);
+ DCHECK_NOT_NULL(tag);
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
0);
uint16_t fall_through = current_function_builder_->AddLocal(kAstI32);
@@ -332,20 +343,20 @@ class AsmWasmBuilderImpl : public AstVisitor {
Scope* scope = expr->scope();
if (in_function_) {
if (expr->bounds().lower->IsFunction()) {
- Type::FunctionType* func_type = expr->bounds().lower->AsFunction();
+ FunctionType* func_type = expr->bounds().lower->AsFunction();
LocalType return_type = TypeFrom(func_type->Result());
current_function_builder_->ReturnType(return_type);
for (int i = 0; i < expr->parameter_count(); i++) {
LocalType type = TypeFrom(func_type->Parameter(i));
- DCHECK(type != kAstStmt);
+ DCHECK_NE(kAstStmt, type);
LookupOrInsertLocal(scope->parameter(i), type);
}
} else {
UNREACHABLE();
}
}
- RECURSE(VisitDeclarations(scope->declarations()));
RECURSE(VisitStatements(expr->body()));
+ RECURSE(VisitDeclarations(scope->declarations()));
}
void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
@@ -363,35 +374,27 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitVariableProxy(VariableProxy* expr) {
if (in_function_) {
Variable* var = expr->var();
- if (var->is_function()) {
- DCHECK(!is_set_op_);
- std::vector<uint8_t> index =
- UnsignedLEB128From(LookupOrInsertFunction(var));
- current_function_builder_->EmitCode(
- &index[0], static_cast<uint32_t>(index.size()));
- } else {
- if (is_set_op_) {
- if (var->IsContextSlot()) {
- current_function_builder_->Emit(kExprStoreGlobal);
- } else {
- current_function_builder_->Emit(kExprSetLocal);
- }
- is_set_op_ = false;
+ if (is_set_op_) {
+ if (var->IsContextSlot()) {
+ current_function_builder_->Emit(kExprStoreGlobal);
} else {
- if (var->IsContextSlot()) {
- current_function_builder_->Emit(kExprLoadGlobal);
- } else {
- current_function_builder_->Emit(kExprGetLocal);
- }
+ current_function_builder_->Emit(kExprSetLocal);
}
- LocalType var_type = TypeOf(expr);
- DCHECK(var_type != kAstStmt);
+ is_set_op_ = false;
+ } else {
if (var->IsContextSlot()) {
- AddLeb128(LookupOrInsertGlobal(var, var_type), false);
+ current_function_builder_->Emit(kExprLoadGlobal);
} else {
- AddLeb128(LookupOrInsertLocal(var, var_type), true);
+ current_function_builder_->Emit(kExprGetLocal);
}
}
+ LocalType var_type = TypeOf(expr);
+ DCHECK_NE(kAstStmt, var_type);
+ if (var->IsContextSlot()) {
+ AddLeb128(LookupOrInsertGlobal(var, var_type), false);
+ } else {
+ AddLeb128(LookupOrInsertLocal(var, var_type), true);
+ }
}
}
@@ -433,10 +436,10 @@ class AsmWasmBuilderImpl : public AstVisitor {
ObjectLiteralProperty* prop = props->at(i);
DCHECK(marking_exported);
VariableProxy* expr = prop->value()->AsVariableProxy();
- DCHECK(expr != nullptr);
+ DCHECK_NOT_NULL(expr);
Variable* var = expr->var();
Literal* name = prop->key()->AsLiteral();
- DCHECK(name != nullptr);
+ DCHECK_NOT_NULL(name);
DCHECK(name->IsPropertyName());
const AstRawString* raw_name = name->AsRawPropertyName();
if (var->is_function()) {
@@ -451,7 +454,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
void LoadInitFunction() {
- current_function_builder_ = builder_->FunctionAt(init_function_index);
+ current_function_builder_ = builder_->FunctionAt(init_function_index_);
in_function_ = true;
}
@@ -460,11 +463,155 @@ class AsmWasmBuilderImpl : public AstVisitor {
current_function_builder_ = nullptr;
}
+ void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
+ FunctionType* func_type =
+ funcs->bounds().lower->AsArray()->Element()->AsFunction();
+ LocalType return_type = TypeFrom(func_type->Result());
+ FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
+ func_type->Arity());
+ if (return_type != kAstStmt) {
+ sig.AddReturn(static_cast<LocalType>(return_type));
+ }
+ for (int i = 0; i < func_type->Arity(); i++) {
+ sig.AddParam(TypeFrom(func_type->Parameter(i)));
+ }
+ uint16_t signature_index = builder_->AddSignature(sig.Build());
+ InsertFunctionTable(table->var(), next_table_index_, signature_index);
+ next_table_index_ += funcs->values()->length();
+ for (int i = 0; i < funcs->values()->length(); i++) {
+ VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
+ DCHECK_NOT_NULL(func);
+ builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
+ }
+ }
+
+ struct FunctionTableIndices : public ZoneObject {
+ uint32_t start_index;
+ uint16_t signature_index;
+ };
+
+ void InsertFunctionTable(Variable* v, uint32_t start_index,
+ uint16_t signature_index) {
+ FunctionTableIndices* container = new (zone()) FunctionTableIndices();
+ container->start_index = start_index;
+ container->signature_index = signature_index;
+ ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
+ v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
+ entry->value = container;
+ }
+
+ FunctionTableIndices* LookupFunctionTable(Variable* v) {
+ ZoneHashMap::Entry* entry =
+ function_tables_.Lookup(v, ComputePointerHash(v));
+ DCHECK_NOT_NULL(entry);
+ return reinterpret_cast<FunctionTableIndices*>(entry->value);
+ }
+
+ class ImportedFunctionTable {
+ private:
+ class ImportedFunctionIndices : public ZoneObject {
+ public:
+ const unsigned char* name_;
+ int name_length_;
+ WasmModuleBuilder::SignatureMap signature_to_index_;
+
+ ImportedFunctionIndices(const unsigned char* name, int name_length,
+ Zone* zone)
+ : name_(name), name_length_(name_length), signature_to_index_(zone) {}
+ };
+ ZoneHashMap table_;
+ AsmWasmBuilderImpl* builder_;
+
+ public:
+ explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
+ : table_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
+ ZoneAllocationPolicy(builder->zone())),
+ builder_(builder) {}
+
+ void AddImport(Variable* v, const unsigned char* name, int name_length) {
+ ImportedFunctionIndices* indices = new (builder_->zone())
+ ImportedFunctionIndices(name, name_length, builder_->zone());
+ ZoneHashMap::Entry* entry = table_.LookupOrInsert(
+ v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
+ entry->value = indices;
+ }
+
+ uint16_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
+ ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
+ DCHECK_NOT_NULL(entry);
+ ImportedFunctionIndices* indices =
+ reinterpret_cast<ImportedFunctionIndices*>(entry->value);
+ WasmModuleBuilder::SignatureMap::iterator pos =
+ indices->signature_to_index_.find(sig);
+ if (pos != indices->signature_to_index_.end()) {
+ return pos->second;
+ } else {
+ uint16_t index = builder_->builder_->AddFunction();
+ indices->signature_to_index_[sig] = index;
+ WasmFunctionBuilder* function = builder_->builder_->FunctionAt(index);
+ function->External(1);
+ function->SetName(indices->name_, indices->name_length_);
+ if (sig->return_count() > 0) {
+ function->ReturnType(sig->GetReturn());
+ }
+ for (size_t i = 0; i < sig->parameter_count(); i++) {
+ function->AddParam(sig->GetParam(i));
+ }
+ return index;
+ }
+ }
+ };
+
void VisitAssignment(Assignment* expr) {
bool in_init = false;
if (!in_function_) {
+ BinaryOperation* binop = expr->value()->AsBinaryOperation();
+ if (binop != nullptr) {
+ Property* prop = binop->left()->AsProperty();
+ DCHECK_NOT_NULL(prop);
+ LoadInitFunction();
+ is_set_op_ = true;
+ RECURSE(Visit(expr->target()));
+ DCHECK(!is_set_op_);
+ if (binop->op() == Token::MUL) {
+ DCHECK(binop->right()->IsLiteral());
+ DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
+ DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
+ VisitForeignVariable(true, prop);
+ } else if (binop->op() == Token::BIT_OR) {
+ DCHECK(binop->right()->IsLiteral());
+ DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
+ DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
+ VisitForeignVariable(false, prop);
+ } else {
+ UNREACHABLE();
+ }
+ UnLoadInitFunction();
+ return;
+ }
// TODO(bradnelson): Get rid of this.
if (TypeOf(expr->value()) == kAstStmt) {
+ Property* prop = expr->value()->AsProperty();
+ if (prop != nullptr) {
+ VariableProxy* vp = prop->obj()->AsVariableProxy();
+ if (vp != nullptr && vp->var()->IsParameter() &&
+ vp->var()->index() == 1) {
+ VariableProxy* target = expr->target()->AsVariableProxy();
+ if (target->bounds().lower->Is(Type::Function())) {
+ const AstRawString* name =
+ prop->key()->AsLiteral()->AsRawPropertyName();
+ imported_function_table_.AddImport(
+ target->var(), name->raw_data(), name->length());
+ }
+ }
+ }
+ ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
+ if (funcs != nullptr &&
+ funcs->bounds().lower->AsArray()->Element()->IsFunction()) {
+ VariableProxy* target = expr->target()->AsVariableProxy();
+ DCHECK_NOT_NULL(target);
+ AddFunctionTable(target, funcs);
+ }
return;
}
in_init = true;
@@ -493,10 +640,59 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitThrow(Throw* expr) { UNREACHABLE(); }
+ void VisitForeignVariable(bool is_float, Property* expr) {
+ DCHECK(expr->obj()->AsVariableProxy());
+ DCHECK(VariableLocation::PARAMETER ==
+ expr->obj()->AsVariableProxy()->var()->location());
+ DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
+ Literal* key_literal = expr->key()->AsLiteral();
+ DCHECK_NOT_NULL(key_literal);
+ if (!key_literal->value().is_null() && !foreign_.is_null() &&
+ foreign_->IsObject()) {
+ Handle<Name> name =
+ i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
+ MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name);
+ if (!maybe_value.is_null()) {
+ Handle<Object> value = maybe_value.ToHandleChecked();
+ if (is_float) {
+ MaybeHandle<Object> maybe_nvalue = i::Object::ToNumber(value);
+ if (!maybe_nvalue.is_null()) {
+ Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
+ if (nvalue->IsNumber()) {
+ double val = nvalue->Number();
+ byte code[] = {WASM_F64(val)};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ return;
+ }
+ }
+ } else {
+ MaybeHandle<Object> maybe_nvalue =
+ i::Object::ToInt32(isolate_, value);
+ if (!maybe_nvalue.is_null()) {
+ Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
+ if (nvalue->IsNumber()) {
+ int32_t val = static_cast<int32_t>(nvalue->Number());
+ byte code[] = {WASM_I32(val)};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ return;
+ }
+ }
+ }
+ }
+ }
+ if (is_float) {
+ byte code[] = {WASM_F64(std::numeric_limits<double>::quiet_NaN())};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ } else {
+ byte code[] = {WASM_I32(0)};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ }
+ }
+
void VisitProperty(Property* expr) {
Expression* obj = expr->obj();
- DCHECK(obj->bounds().lower == obj->bounds().upper);
- TypeImpl<ZoneTypeConfig>* type = obj->bounds().lower;
+ DCHECK_EQ(obj->bounds().lower, obj->bounds().upper);
+ Type* type = obj->bounds().lower;
MachineType mtype;
int size;
if (type->Is(cache_.kUint8Array)) {
@@ -533,29 +729,38 @@ class AsmWasmBuilderImpl : public AstVisitor {
WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_),
WasmOpcodes::LoadStoreAccessOf(false));
is_set_op_ = false;
- Literal* value = expr->key()->AsLiteral();
- if (value) {
- DCHECK(value->raw_value()->IsNumber());
- DCHECK(kAstI32 == TypeOf(value));
- int val = static_cast<int>(value->raw_value()->AsNumber());
- byte code[] = {WASM_I32(val * size)};
- current_function_builder_->EmitCode(code, sizeof(code));
- return;
- }
- BinaryOperation* binop = expr->key()->AsBinaryOperation();
- if (binop) {
- DCHECK(Token::SAR == binop->op());
- DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
- DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
- DCHECK(size ==
- 1 << static_cast<int>(
- binop->right()->AsLiteral()->raw_value()->AsNumber()));
- // Mask bottom bits to match asm.js behavior.
- current_function_builder_->Emit(kExprI32And);
- byte code[] = {WASM_I8(~(size - 1))};
- current_function_builder_->EmitCode(code, sizeof(code));
- RECURSE(Visit(binop->left()));
+ if (size == 1) {
+ // Allow more general expression in byte arrays than the spec
+ // strictly permits.
+ // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
+ // places that strictly should be HEAP8[HEAP32[..]>>0].
+ RECURSE(Visit(expr->key()));
return;
+ } else {
+ Literal* value = expr->key()->AsLiteral();
+ if (value) {
+ DCHECK(value->raw_value()->IsNumber());
+ DCHECK_EQ(kAstI32, TypeOf(value));
+ int val = static_cast<int>(value->raw_value()->AsNumber());
+ byte code[] = {WASM_I32(val * size)};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ return;
+ }
+ BinaryOperation* binop = expr->key()->AsBinaryOperation();
+ if (binop) {
+ DCHECK_EQ(Token::SAR, binop->op());
+ DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
+ DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
+ DCHECK_EQ(size,
+ 1 << static_cast<int>(
+ binop->right()->AsLiteral()->raw_value()->AsNumber()));
+ // Mask bottom bits to match asm.js behavior.
+ current_function_builder_->Emit(kExprI32And);
+ byte code[] = {WASM_I8(~(size - 1))};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ RECURSE(Visit(binop->left()));
+ return;
+ }
}
UNREACHABLE();
}
@@ -565,18 +770,54 @@ class AsmWasmBuilderImpl : public AstVisitor {
switch (call_type) {
case Call::OTHER_CALL: {
DCHECK(in_function_);
- current_function_builder_->Emit(kExprCallFunction);
- RECURSE(Visit(expr->expression()));
- ZoneList<Expression*>* args = expr->arguments();
- for (int i = 0; i < args->length(); ++i) {
- Expression* arg = args->at(i);
- RECURSE(Visit(arg));
+ uint16_t index;
+ VariableProxy* vp = expr->expression()->AsVariableProxy();
+ if (vp != nullptr &&
+ Type::Any()->Is(vp->bounds().lower->AsFunction()->Result())) {
+ LocalType return_type = TypeOf(expr);
+ ZoneList<Expression*>* args = expr->arguments();
+ FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
+ args->length());
+ if (return_type != kAstStmt) {
+ sig.AddReturn(return_type);
+ }
+ for (int i = 0; i < args->length(); i++) {
+ sig.AddParam(TypeOf(args->at(i)));
+ }
+ index =
+ imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
+ } else {
+ index = LookupOrInsertFunction(vp->var());
}
+ current_function_builder_->Emit(kExprCallFunction);
+ std::vector<uint8_t> index_arr = UnsignedLEB128From(index);
+ current_function_builder_->EmitCode(
+ &index_arr[0], static_cast<uint32_t>(index_arr.size()));
+ break;
+ }
+ case Call::KEYED_PROPERTY_CALL: {
+ DCHECK(in_function_);
+ Property* p = expr->expression()->AsProperty();
+ DCHECK_NOT_NULL(p);
+ VariableProxy* var = p->obj()->AsVariableProxy();
+ DCHECK_NOT_NULL(var);
+ FunctionTableIndices* indices = LookupFunctionTable(var->var());
+ current_function_builder_->EmitWithU8(kExprCallIndirect,
+ indices->signature_index);
+ current_function_builder_->Emit(kExprI32Add);
+ byte code[] = {WASM_I32(indices->start_index)};
+ current_function_builder_->EmitCode(code, sizeof(code));
+ RECURSE(Visit(p->key()));
break;
}
default:
UNREACHABLE();
}
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ RECURSE(Visit(arg));
+ }
}
void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
@@ -586,7 +827,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) {
case Token::NOT: {
- DCHECK(TypeOf(expr->expression()) == kAstI32);
+ DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
current_function_builder_->Emit(kExprBoolNot);
break;
}
@@ -600,7 +841,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
int32_t val) {
- DCHECK(expr->right() != nullptr);
+ DCHECK_NOT_NULL(expr->right());
if (expr->op() == op && expr->right()->IsLiteral() &&
TypeOf(expr) == kAstI32) {
Literal* right = expr->right()->AsLiteral();
@@ -614,7 +855,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
double val) {
- DCHECK(expr->right() != nullptr);
+ DCHECK_NOT_NULL(expr->right());
if (expr->op() == op && expr->right()->IsLiteral() &&
TypeOf(expr) == kAstF64) {
Literal* right = expr->right()->AsLiteral();
@@ -629,8 +870,9 @@ class AsmWasmBuilderImpl : public AstVisitor {
enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
ConvertOperation MatchOr(BinaryOperation* expr) {
- if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0)) {
- return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
+ if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
+ (TypeOf(expr->left()) == kAstI32)) {
+ return kAsIs;
} else {
return kNone;
}
@@ -647,12 +889,12 @@ class AsmWasmBuilderImpl : public AstVisitor {
ConvertOperation MatchXor(BinaryOperation* expr) {
if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
- DCHECK(TypeOf(expr->left()) == kAstI32);
- DCHECK(TypeOf(expr->right()) == kAstI32);
+ DCHECK_EQ(kAstI32, TypeOf(expr->left()));
+ DCHECK_EQ(kAstI32, TypeOf(expr->right()));
BinaryOperation* op = expr->left()->AsBinaryOperation();
if (op != nullptr) {
if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
- DCHECK(TypeOf(op->right()) == kAstI32);
+ DCHECK_EQ(kAstI32, TypeOf(op->right()));
if (TypeOf(op->left()) != kAstI32) {
return kToInt;
} else {
@@ -666,7 +908,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
ConvertOperation MatchMul(BinaryOperation* expr) {
if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
- DCHECK(TypeOf(expr->right()) == kAstF64);
+ DCHECK_EQ(kAstF64, TypeOf(expr->right()));
if (TypeOf(expr->left()) != kAstF64) {
return kToDouble;
} else {
@@ -768,6 +1010,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
+ BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
@@ -786,6 +1029,10 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
break;
}
+ case Token::COMMA: {
+ current_function_builder_->EmitWithU8(kExprBlock, 2);
+ break;
+ }
default:
UNREACHABLE();
}
@@ -879,8 +1126,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
TypeIndex TypeIndexOf(Expression* expr) {
- DCHECK(expr->bounds().lower == expr->bounds().upper);
- TypeImpl<ZoneTypeConfig>* type = expr->bounds().lower;
+ DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
+ Type* type = expr->bounds().lower;
if (type->Is(cache_.kAsmFixnum)) {
return kFixnum;
} else if (type->Is(cache_.kAsmSigned)) {
@@ -929,17 +1176,14 @@ class AsmWasmBuilderImpl : public AstVisitor {
void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
- void VisitRewritableAssignmentExpression(
- RewritableAssignmentExpression* expr) {
- UNREACHABLE();
- }
+ void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
struct IndexContainer : public ZoneObject {
uint16_t index;
};
uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
- DCHECK(current_function_builder_ != nullptr);
+ DCHECK_NOT_NULL(current_function_builder_);
ZoneHashMap::Entry* entry =
local_variables_.Lookup(v, ComputePointerHash(v));
if (entry == nullptr) {
@@ -974,7 +1218,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
uint16_t LookupOrInsertFunction(Variable* v) {
- DCHECK(builder_ != nullptr);
+ DCHECK_NOT_NULL(builder_);
ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
if (entry == nullptr) {
uint16_t index = builder_->AddFunction();
@@ -988,11 +1232,11 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
LocalType TypeOf(Expression* expr) {
- DCHECK(expr->bounds().lower == expr->bounds().upper);
+ DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
return TypeFrom(expr->bounds().lower);
}
- LocalType TypeFrom(TypeImpl<ZoneTypeConfig>* type) {
+ LocalType TypeFrom(Type* type) {
if (type->Is(cache_.kAsmInt)) {
return kAstI32;
} else if (type->Is(cache_.kAsmFloat)) {
@@ -1017,10 +1261,14 @@ class AsmWasmBuilderImpl : public AstVisitor {
FunctionLiteral* literal_;
Isolate* isolate_;
Zone* zone_;
+ Handle<Object> foreign_;
TypeCache const& cache_;
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
int block_size_;
- uint16_t init_function_index;
+ uint16_t init_function_index_;
+ uint32_t next_table_index_;
+ ZoneHashMap function_tables_;
+ ImportedFunctionTable imported_function_table_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
@@ -1029,13 +1277,13 @@ class AsmWasmBuilderImpl : public AstVisitor {
};
AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
- FunctionLiteral* literal)
- : isolate_(isolate), zone_(zone), literal_(literal) {}
+ FunctionLiteral* literal, Handle<Object> foreign)
+ : isolate_(isolate), zone_(zone), literal_(literal), foreign_(foreign) {}
// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
// that zone in constructor may be thrown away once wasm module is written.
WasmModuleIndex* AsmWasmBuilder::Run() {
- AsmWasmBuilderImpl impl(isolate_, zone_, literal_);
+ AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_);
impl.Compile();
WasmModuleWriter* writer = impl.builder_->Build(zone_);
return writer->WriteTo(zone_);
diff --git a/deps/v8/src/wasm/asm-wasm-builder.h b/deps/v8/src/wasm/asm-wasm-builder.h
index cb568db77c..9b761f9040 100644
--- a/deps/v8/src/wasm/asm-wasm-builder.h
+++ b/deps/v8/src/wasm/asm-wasm-builder.h
@@ -6,6 +6,7 @@
#define V8_WASM_ASM_WASM_BUILDER_H_
#include "src/allocation.h"
+#include "src/objects.h"
#include "src/wasm/encoder.h"
#include "src/zone.h"
@@ -18,13 +19,15 @@ namespace wasm {
class AsmWasmBuilder {
public:
- explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root);
+ explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root,
+ Handle<Object> foreign);
WasmModuleIndex* Run();
private:
Isolate* isolate_;
Zone* zone_;
FunctionLiteral* literal_;
+ Handle<Object> foreign_;
};
} // namespace wasm
} // namespace internal
diff --git a/deps/v8/src/wasm/ast-decoder.cc b/deps/v8/src/wasm/ast-decoder.cc
index ffb815771a..c97c781c12 100644
--- a/deps/v8/src/wasm/ast-decoder.cc
+++ b/deps/v8/src/wasm/ast-decoder.cc
@@ -5,6 +5,7 @@
#include "src/base/platform/elapsed-timer.h"
#include "src/signature.h"
+#include "src/bit-vector.h"
#include "src/flags.h"
#include "src/handles.h"
#include "src/zone-containers.h"
@@ -40,7 +41,6 @@ struct Tree {
WasmOpcode opcode() const { return static_cast<WasmOpcode>(*pc); }
};
-
// A production represents an incomplete decoded tree in the LR decoder.
struct Production {
Tree* tree; // the root of the syntax tree.
@@ -97,13 +97,278 @@ struct IfEnv {
#define BUILD0(func) (build() ? builder_->func() : nullptr)
+// Generic Wasm bytecode decoder with utilities for decoding operands,
+// lengths, etc.
+class WasmDecoder : public Decoder {
+ public:
+ WasmDecoder() : Decoder(nullptr, nullptr), function_env_(nullptr) {}
+ WasmDecoder(FunctionEnv* env, const byte* start, const byte* end)
+ : Decoder(start, end), function_env_(env) {}
+ FunctionEnv* function_env_;
+
+ void Reset(FunctionEnv* function_env, const byte* start, const byte* end) {
+ Decoder::Reset(start, end);
+ function_env_ = function_env;
+ }
+
+ byte ByteOperand(const byte* pc, const char* msg = "missing 1-byte operand") {
+ if ((pc + sizeof(byte)) >= limit_) {
+ error(pc, msg);
+ return 0;
+ }
+ return pc[1];
+ }
+
+ uint32_t Uint32Operand(const byte* pc) {
+ if ((pc + sizeof(uint32_t)) >= limit_) {
+ error(pc, "missing 4-byte operand");
+ return 0;
+ }
+ return read_u32(pc + 1);
+ }
+
+ uint64_t Uint64Operand(const byte* pc) {
+ if ((pc + sizeof(uint64_t)) >= limit_) {
+ error(pc, "missing 8-byte operand");
+ return 0;
+ }
+ return read_u64(pc + 1);
+ }
+
+ inline bool Validate(const byte* pc, LocalIndexOperand& operand) {
+ if (operand.index < function_env_->total_locals) {
+ operand.type = function_env_->GetLocalType(operand.index);
+ return true;
+ }
+ error(pc, pc + 1, "invalid local index");
+ return false;
+ }
+
+ inline bool Validate(const byte* pc, GlobalIndexOperand& operand) {
+ ModuleEnv* m = function_env_->module;
+ if (m && m->module && operand.index < m->module->globals->size()) {
+ operand.machine_type = m->module->globals->at(operand.index).type;
+ operand.type = WasmOpcodes::LocalTypeFor(operand.machine_type);
+ return true;
+ }
+ error(pc, pc + 1, "invalid global index");
+ return false;
+ }
+
+ inline bool Validate(const byte* pc, FunctionIndexOperand& operand) {
+ ModuleEnv* m = function_env_->module;
+ if (m && m->module && operand.index < m->module->functions->size()) {
+ operand.sig = m->module->functions->at(operand.index).sig;
+ return true;
+ }
+ error(pc, pc + 1, "invalid function index");
+ return false;
+ }
+
+ inline bool Validate(const byte* pc, SignatureIndexOperand& operand) {
+ ModuleEnv* m = function_env_->module;
+ if (m && m->module && operand.index < m->module->signatures->size()) {
+ operand.sig = m->module->signatures->at(operand.index);
+ return true;
+ }
+ error(pc, pc + 1, "invalid signature index");
+ return false;
+ }
+
+ inline bool Validate(const byte* pc, ImportIndexOperand& operand) {
+ ModuleEnv* m = function_env_->module;
+ if (m && m->module && operand.index < m->module->import_table->size()) {
+ operand.sig = m->module->import_table->at(operand.index).sig;
+ return true;
+ }
+ error(pc, pc + 1, "invalid signature index");
+ return false;
+ }
+
+ inline bool Validate(const byte* pc, BreakDepthOperand& operand,
+ ZoneVector<Block>& blocks) {
+ if (operand.depth < blocks.size()) {
+ operand.target = &blocks[blocks.size() - operand.depth - 1];
+ return true;
+ }
+ error(pc, pc + 1, "invalid break depth");
+ return false;
+ }
+
+ bool Validate(const byte* pc, TableSwitchOperand& operand,
+ size_t block_depth) {
+ if (operand.table_count == 0) {
+ error(pc, "tableswitch with 0 entries");
+ return false;
+ }
+ // Verify table.
+ for (uint32_t i = 0; i < operand.table_count; i++) {
+ uint16_t target = operand.read_entry(this, i);
+ if (target >= 0x8000) {
+ size_t depth = target - 0x8000;
+ if (depth > block_depth) {
+ error(operand.table + i * 2, "improper branch in tableswitch");
+ return false;
+ }
+ } else {
+ if (target >= operand.case_count) {
+ error(operand.table + i * 2, "invalid case target in tableswitch");
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ int OpcodeArity(const byte* pc) {
+#define DECLARE_ARITY(name, ...) \
+ static const LocalType kTypes_##name[] = {__VA_ARGS__}; \
+ static const int kArity_##name = \
+ static_cast<int>(arraysize(kTypes_##name) - 1);
+
+ FOREACH_SIGNATURE(DECLARE_ARITY);
+#undef DECLARE_ARITY
+
+ switch (static_cast<WasmOpcode>(*pc)) {
+ case kExprI8Const:
+ case kExprI32Const:
+ case kExprI64Const:
+ case kExprF64Const:
+ case kExprF32Const:
+ case kExprGetLocal:
+ case kExprLoadGlobal:
+ case kExprNop:
+ case kExprUnreachable:
+ return 0;
+
+ case kExprBr:
+ case kExprStoreGlobal:
+ case kExprSetLocal:
+ return 1;
+
+ case kExprIf:
+ case kExprBrIf:
+ return 2;
+ case kExprIfElse:
+ case kExprSelect:
+ return 3;
+
+ case kExprBlock:
+ case kExprLoop: {
+ BlockCountOperand operand(this, pc);
+ return operand.count;
+ }
+
+ case kExprCallFunction: {
+ FunctionIndexOperand operand(this, pc);
+ return static_cast<int>(
+ function_env_->module->GetFunctionSignature(operand.index)
+ ->parameter_count());
+ }
+ case kExprCallIndirect: {
+ SignatureIndexOperand operand(this, pc);
+ return 1 + static_cast<int>(
+ function_env_->module->GetSignature(operand.index)
+ ->parameter_count());
+ }
+ case kExprCallImport: {
+ ImportIndexOperand operand(this, pc);
+ return static_cast<int>(
+ function_env_->module->GetImportSignature(operand.index)
+ ->parameter_count());
+ }
+ case kExprReturn: {
+ return static_cast<int>(function_env_->sig->return_count());
+ }
+ case kExprTableSwitch: {
+ TableSwitchOperand operand(this, pc);
+ return 1 + operand.case_count;
+ }
+
+#define DECLARE_OPCODE_CASE(name, opcode, sig) \
+ case kExpr##name: \
+ return kArity_##sig;
+
+ FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
+ FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
+ FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
+ FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
+#undef DECLARE_OPCODE_CASE
+ }
+ UNREACHABLE();
+ return 0;
+ }
+
+ int OpcodeLength(const byte* pc) {
+ switch (static_cast<WasmOpcode>(*pc)) {
+#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
+ FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
+ FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
+#undef DECLARE_OPCODE_CASE
+ {
+ MemoryAccessOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprBlock:
+ case kExprLoop: {
+ BlockCountOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprBr:
+ case kExprBrIf: {
+ BreakDepthOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprStoreGlobal:
+ case kExprLoadGlobal: {
+ GlobalIndexOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+
+ case kExprCallFunction: {
+ FunctionIndexOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprCallIndirect: {
+ SignatureIndexOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprCallImport: {
+ ImportIndexOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+
+ case kExprSetLocal:
+ case kExprGetLocal: {
+ LocalIndexOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprTableSwitch: {
+ TableSwitchOperand operand(this, pc);
+ return 1 + operand.length;
+ }
+ case kExprI8Const:
+ return 2;
+ case kExprI32Const:
+ case kExprF32Const:
+ return 5;
+ case kExprI64Const:
+ case kExprF64Const:
+ return 9;
+
+ default:
+ return 1;
+ }
+ }
+};
+
+
// A shift-reduce-parser strategy for decoding Wasm code that uses an explicit
// shift-reduce strategy with multiple internal stacks.
-class LR_WasmDecoder : public Decoder {
+class LR_WasmDecoder : public WasmDecoder {
public:
LR_WasmDecoder(Zone* zone, TFBuilder* builder)
- : Decoder(nullptr, nullptr),
- zone_(zone),
+ : zone_(zone),
builder_(builder),
trees_(zone),
stack_(zone),
@@ -127,8 +392,7 @@ class LR_WasmDecoder : public Decoder {
}
base_ = base;
- Reset(pc, end);
- function_env_ = function_env;
+ Reset(function_env, pc, end);
InitSsaEnv();
DecodeFunctionBody();
@@ -151,15 +415,20 @@ class LR_WasmDecoder : public Decoder {
}
if (ok()) {
+ if (FLAG_trace_wasm_ast) {
+ PrintAst(function_env, pc, end);
+ }
if (FLAG_trace_wasm_decode_time) {
double ms = decode_timer.Elapsed().InMillisecondsF();
- PrintF(" - decoding took %0.3f ms\n", ms);
+ PrintF("wasm-decode ok (%0.3f ms)\n\n", ms);
+ } else {
+ TRACE("wasm-decode ok\n\n");
}
- TRACE("wasm-decode ok\n\n");
} else {
TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_),
startrel(error_pc_), error_msg_.get());
}
+
return toResult(tree);
}
@@ -172,7 +441,6 @@ class LR_WasmDecoder : public Decoder {
TreeResult result_;
SsaEnv* ssa_env_;
- FunctionEnv* function_env_;
ZoneVector<Tree*> trees_;
ZoneVector<Production> stack_;
@@ -199,30 +467,30 @@ class LR_WasmDecoder : public Decoder {
ssa_env->locals[pos++] = builder_->Param(i, sig->GetParam(i));
}
// Initialize int32 locals.
- if (function_env_->local_int32_count > 0) {
+ if (function_env_->local_i32_count > 0) {
TFNode* zero = builder_->Int32Constant(0);
- for (uint32_t i = 0; i < function_env_->local_int32_count; i++) {
+ for (uint32_t i = 0; i < function_env_->local_i32_count; i++) {
ssa_env->locals[pos++] = zero;
}
}
// Initialize int64 locals.
- if (function_env_->local_int64_count > 0) {
+ if (function_env_->local_i64_count > 0) {
TFNode* zero = builder_->Int64Constant(0);
- for (uint32_t i = 0; i < function_env_->local_int64_count; i++) {
+ for (uint32_t i = 0; i < function_env_->local_i64_count; i++) {
ssa_env->locals[pos++] = zero;
}
}
// Initialize float32 locals.
- if (function_env_->local_float32_count > 0) {
+ if (function_env_->local_f32_count > 0) {
TFNode* zero = builder_->Float32Constant(0);
- for (uint32_t i = 0; i < function_env_->local_float32_count; i++) {
+ for (uint32_t i = 0; i < function_env_->local_f32_count; i++) {
ssa_env->locals[pos++] = zero;
}
}
// Initialize float64 locals.
- if (function_env_->local_float64_count > 0) {
+ if (function_env_->local_f64_count > 0) {
TFNode* zero = builder_->Float64Constant(0);
- for (uint32_t i = 0; i < function_env_->local_float64_count; i++) {
+ for (uint32_t i = 0; i < function_env_->local_f64_count; i++) {
ssa_env->locals[pos++] = zero;
}
}
@@ -329,25 +597,25 @@ class LR_WasmDecoder : public Decoder {
Leaf(kAstStmt);
break;
case kExprBlock: {
- int length = Operand<uint8_t>(pc_);
- if (length < 1) {
+ BlockCountOperand operand(this, pc_);
+ if (operand.count < 1) {
Leaf(kAstStmt);
} else {
- Shift(kAstEnd, length);
+ Shift(kAstEnd, operand.count);
// The break environment is the outer environment.
SsaEnv* break_env = ssa_env_;
PushBlock(break_env);
SetEnv("block:start", Steal(break_env));
}
- len = 2;
+ len = 1 + operand.length;
break;
}
case kExprLoop: {
- int length = Operand<uint8_t>(pc_);
- if (length < 1) {
+ BlockCountOperand operand(this, pc_);
+ if (operand.count < 1) {
Leaf(kAstStmt);
} else {
- Shift(kAstEnd, length);
+ Shift(kAstEnd, operand.count);
// The break environment is the outer environment.
SsaEnv* break_env = ssa_env_;
PushBlock(break_env);
@@ -359,7 +627,7 @@ class LR_WasmDecoder : public Decoder {
PushBlock(cont_env);
blocks_.back().stack_depth = -1; // no production for inner block.
}
- len = 2;
+ len = 1 + operand.length;
break;
}
case kExprIf:
@@ -372,59 +640,27 @@ class LR_WasmDecoder : public Decoder {
Shift(kAstStmt, 3); // Result type is typeof(x) in {c ? x : y}.
break;
case kExprBr: {
- uint32_t depth = Operand<uint8_t>(pc_);
- Shift(kAstEnd, 1);
- if (depth >= blocks_.size()) {
- error("improperly nested branch");
+ BreakDepthOperand operand(this, pc_);
+ if (Validate(pc_, operand, blocks_)) {
+ Shift(kAstEnd, 1);
}
- len = 2;
+ len = 1 + operand.length;
break;
}
case kExprBrIf: {
- uint32_t depth = Operand<uint8_t>(pc_);
- Shift(kAstStmt, 2);
- if (depth >= blocks_.size()) {
- error("improperly nested conditional branch");
+ BreakDepthOperand operand(this, pc_);
+ if (Validate(pc_, operand, blocks_)) {
+ Shift(kAstStmt, 2);
}
- len = 2;
+ len = 1 + operand.length;
break;
}
case kExprTableSwitch: {
- if (!checkAvailable(5)) {
- error("expected #tableswitch <cases> <table>, fell off end");
- break;
- }
- uint16_t case_count = *reinterpret_cast<const uint16_t*>(pc_ + 1);
- uint16_t table_count = *reinterpret_cast<const uint16_t*>(pc_ + 3);
- len = 5 + table_count * 2;
-
- if (table_count == 0) {
- error("tableswitch with 0 entries");
- break;
- }
-
- if (!checkAvailable(len)) {
- error("expected #tableswitch <cases> <table>, fell off end");
- break;
- }
-
- Shift(kAstEnd, 1 + case_count);
-
- // Verify table.
- for (int i = 0; i < table_count; i++) {
- uint16_t target =
- *reinterpret_cast<const uint16_t*>(pc_ + 5 + i * 2);
- if (target >= 0x8000) {
- size_t depth = target - 0x8000;
- if (depth > blocks_.size()) {
- error(pc_ + 5 + i * 2, "improper branch in tableswitch");
- }
- } else {
- if (target >= case_count) {
- error(pc_ + 5 + i * 2, "invalid case target in tableswitch");
- }
- }
+ TableSwitchOperand operand(this, pc_);
+ if (Validate(pc_, operand, blocks_.size())) {
+ Shift(kAstEnd, 1 + operand.case_count);
}
+ len = 1 + operand.length;
break;
}
case kExprReturn: {
@@ -445,59 +681,66 @@ class LR_WasmDecoder : public Decoder {
break;
}
case kExprI8Const: {
- int32_t value = Operand<int8_t>(pc_);
- Leaf(kAstI32, BUILD(Int32Constant, value));
- len = 2;
+ ImmI8Operand operand(this, pc_);
+ Leaf(kAstI32, BUILD(Int32Constant, operand.value));
+ len = 1 + operand.length;
break;
}
case kExprI32Const: {
- int32_t value = Operand<int32_t>(pc_);
- Leaf(kAstI32, BUILD(Int32Constant, value));
- len = 5;
+ ImmI32Operand operand(this, pc_);
+ Leaf(kAstI32, BUILD(Int32Constant, operand.value));
+ len = 1 + operand.length;
break;
}
case kExprI64Const: {
- int64_t value = Operand<int64_t>(pc_);
- Leaf(kAstI64, BUILD(Int64Constant, value));
- len = 9;
+ ImmI64Operand operand(this, pc_);
+ Leaf(kAstI64, BUILD(Int64Constant, operand.value));
+ len = 1 + operand.length;
break;
}
case kExprF32Const: {
- float value = Operand<float>(pc_);
- Leaf(kAstF32, BUILD(Float32Constant, value));
- len = 5;
+ ImmF32Operand operand(this, pc_);
+ Leaf(kAstF32, BUILD(Float32Constant, operand.value));
+ len = 1 + operand.length;
break;
}
case kExprF64Const: {
- double value = Operand<double>(pc_);
- Leaf(kAstF64, BUILD(Float64Constant, value));
- len = 9;
+ ImmF64Operand operand(this, pc_);
+ Leaf(kAstF64, BUILD(Float64Constant, operand.value));
+ len = 1 + operand.length;
break;
}
case kExprGetLocal: {
- uint32_t index;
- LocalType type = LocalOperand(pc_, &index, &len);
- TFNode* val =
- build() && type != kAstStmt ? ssa_env_->locals[index] : nullptr;
- Leaf(type, val);
+ LocalIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ TFNode* val = build() ? ssa_env_->locals[operand.index] : nullptr;
+ Leaf(operand.type, val);
+ }
+ len = 1 + operand.length;
break;
}
case kExprSetLocal: {
- uint32_t index;
- LocalType type = LocalOperand(pc_, &index, &len);
- Shift(type, 1);
+ LocalIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ Shift(operand.type, 1);
+ }
+ len = 1 + operand.length;
break;
}
case kExprLoadGlobal: {
- uint32_t index;
- LocalType type = GlobalOperand(pc_, &index, &len);
- Leaf(type, BUILD(LoadGlobal, index));
+ GlobalIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ Leaf(operand.type, BUILD(LoadGlobal, operand.index));
+ }
+ len = 1 + operand.length;
break;
}
case kExprStoreGlobal: {
- uint32_t index;
- LocalType type = GlobalOperand(pc_, &index, &len);
- Shift(type, 1);
+ GlobalIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ Shift(operand.type, 1);
+ }
+ len = 1 + operand.length;
break;
}
case kExprI32LoadMem8S:
@@ -546,27 +789,36 @@ class LR_WasmDecoder : public Decoder {
Shift(kAstI32, 1);
break;
case kExprCallFunction: {
- uint32_t unused;
- FunctionSig* sig = FunctionSigOperand(pc_, &unused, &len);
- if (sig) {
- LocalType type =
- sig->return_count() == 0 ? kAstStmt : sig->GetReturn();
- Shift(type, static_cast<int>(sig->parameter_count()));
- } else {
- Leaf(kAstI32); // error
+ FunctionIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ LocalType type = operand.sig->return_count() == 0
+ ? kAstStmt
+ : operand.sig->GetReturn();
+ Shift(type, static_cast<int>(operand.sig->parameter_count()));
}
+ len = 1 + operand.length;
break;
}
case kExprCallIndirect: {
- uint32_t unused;
- FunctionSig* sig = SigOperand(pc_, &unused, &len);
- if (sig) {
- LocalType type =
- sig->return_count() == 0 ? kAstStmt : sig->GetReturn();
- Shift(type, static_cast<int>(1 + sig->parameter_count()));
- } else {
- Leaf(kAstI32); // error
+ SignatureIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ LocalType type = operand.sig->return_count() == 0
+ ? kAstStmt
+ : operand.sig->GetReturn();
+ Shift(type, static_cast<int>(1 + operand.sig->parameter_count()));
}
+ len = 1 + operand.length;
+ break;
+ }
+ case kExprCallImport: {
+ ImportIndexOperand operand(this, pc_);
+ if (Validate(pc_, operand)) {
+ LocalType type = operand.sig->return_count() == 0
+ ? kAstStmt
+ : operand.sig->GetReturn();
+ Shift(type, static_cast<int>(operand.sig->parameter_count()));
+ }
+ len = 1 + operand.length;
break;
}
default:
@@ -589,19 +841,15 @@ class LR_WasmDecoder : public Decoder {
}
int DecodeLoadMem(const byte* pc, LocalType type) {
- int length = 2;
- uint32_t offset;
- MemoryAccessOperand(pc, &length, &offset);
+ MemoryAccessOperand operand(this, pc);
Shift(type, 1);
- return length;
+ return 1 + operand.length;
}
int DecodeStoreMem(const byte* pc, LocalType type) {
- int length = 2;
- uint32_t offset;
- MemoryAccessOperand(pc, &length, &offset);
+ MemoryAccessOperand operand(this, pc);
Shift(type, 2);
- return length;
+ return 1 + operand.length;
}
void AddImplicitReturnAtEnd() {
@@ -747,26 +995,26 @@ class LR_WasmDecoder : public Decoder {
}
case kExprSelect: {
if (p->index == 1) {
- // Condition done.
- TypeCheckLast(p, kAstI32);
- } else if (p->index == 2) {
// True expression done.
p->tree->type = p->last()->type;
if (p->tree->type == kAstStmt) {
error(p->pc(), p->tree->children[1]->pc,
"select operand should be expression");
}
- } else {
+ } else if (p->index == 2) {
// False expression done.
- DCHECK(p->done());
TypeCheckLast(p, p->tree->type);
+ } else {
+ // Condition done.
+ DCHECK(p->done());
+ TypeCheckLast(p, kAstI32);
if (build()) {
TFNode* controls[2];
- builder_->Branch(p->tree->children[0]->node, &controls[0],
+ builder_->Branch(p->tree->children[2]->node, &controls[0],
&controls[1]);
TFNode* merge = builder_->Merge(2, controls);
- TFNode* vals[2] = {p->tree->children[1]->node,
- p->tree->children[2]->node};
+ TFNode* vals[2] = {p->tree->children[0]->node,
+ p->tree->children[1]->node};
TFNode* phi = builder_->Phi(p->tree->type, 2, vals, merge);
p->tree->node = phi;
ssa_env_->control = merge;
@@ -775,64 +1023,44 @@ class LR_WasmDecoder : public Decoder {
break;
}
case kExprBr: {
- uint32_t depth = Operand<uint8_t>(p->pc());
- if (depth >= blocks_.size()) {
- error("improperly nested branch");
- break;
- }
- Block* block = &blocks_[blocks_.size() - depth - 1];
- ReduceBreakToExprBlock(p, block);
+ BreakDepthOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand, blocks_));
+ ReduceBreakToExprBlock(p, operand.target);
break;
}
case kExprBrIf: {
- if (p->index == 1) {
+ if (p->done()) {
TypeCheckLast(p, kAstI32);
- } else if (p->done()) {
- uint32_t depth = Operand<uint8_t>(p->pc());
- if (depth >= blocks_.size()) {
- error("improperly nested branch");
- break;
- }
- Block* block = &blocks_[blocks_.size() - depth - 1];
+ BreakDepthOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand, blocks_));
SsaEnv* fenv = ssa_env_;
SsaEnv* tenv = Split(fenv);
- BUILD(Branch, p->tree->children[0]->node, &tenv->control,
+ BUILD(Branch, p->tree->children[1]->node, &tenv->control,
&fenv->control);
ssa_env_ = tenv;
- ReduceBreakToExprBlock(p, block);
+ ReduceBreakToExprBlock(p, operand.target, p->tree->children[0]);
ssa_env_ = fenv;
}
break;
}
case kExprTableSwitch: {
- uint16_t table_count = *reinterpret_cast<const uint16_t*>(p->pc() + 3);
- if (table_count == 1) {
- // Degenerate switch with only a default target.
- if (p->index == 1) {
- SsaEnv* break_env = ssa_env_;
- PushBlock(break_env);
- SetEnv("switch:default", Steal(break_env));
- }
- if (p->done()) {
- Block* block = &blocks_.back();
- // fall through to the end.
- ReduceBreakToExprBlock(p, block);
- SetEnv("switch:end", block->ssa_env);
- blocks_.pop_back();
- }
- break;
- }
-
if (p->index == 1) {
// Switch key finished.
TypeCheckLast(p, kAstI32);
+ if (failed()) break;
+
+ TableSwitchOperand operand(this, p->pc());
+ DCHECK(Validate(p->pc(), operand, blocks_.size()));
- TFNode* sw = BUILD(Switch, table_count, p->last()->node);
+ // Build the switch only if it has more than just a default target.
+ bool build_switch = operand.table_count > 1;
+ TFNode* sw = nullptr;
+ if (build_switch)
+ sw = BUILD(Switch, operand.table_count, p->last()->node);
// Allocate environments for each case.
- uint16_t case_count = *reinterpret_cast<const uint16_t*>(p->pc() + 1);
- SsaEnv** case_envs = zone_->NewArray<SsaEnv*>(case_count);
- for (int i = 0; i < case_count; i++) {
+ SsaEnv** case_envs = zone_->NewArray<SsaEnv*>(operand.case_count);
+ for (uint32_t i = 0; i < operand.case_count; i++) {
case_envs[i] = UnreachableEnv();
}
@@ -843,13 +1071,15 @@ class LR_WasmDecoder : public Decoder {
ssa_env_ = copy;
// Build the environments for each case based on the table.
- const uint16_t* table =
- reinterpret_cast<const uint16_t*>(p->pc() + 5);
- for (int i = 0; i < table_count; i++) {
- uint16_t target = table[i];
- SsaEnv* env = Split(copy);
- env->control = (i == table_count - 1) ? BUILD(IfDefault, sw)
- : BUILD(IfValue, i, sw);
+ for (uint32_t i = 0; i < operand.table_count; i++) {
+ uint16_t target = operand.read_entry(this, i);
+ SsaEnv* env = copy;
+ if (build_switch) {
+ env = Split(env);
+ env->control = (i == operand.table_count - 1)
+ ? BUILD(IfDefault, sw)
+ : BUILD(IfValue, i, sw);
+ }
if (target >= 0x8000) {
// Targets an outer block.
int depth = target - 0x8000;
@@ -860,25 +1090,21 @@ class LR_WasmDecoder : public Decoder {
Goto(env, case_envs[target]);
}
}
+ }
- // Switch to the environment for the first case.
- SetEnv("switch:case", case_envs[0]);
+ if (p->done()) {
+ // Last case. Fall through to the end.
+ Block* block = &blocks_.back();
+ if (p->index > 1) ReduceBreakToExprBlock(p, block);
+ SsaEnv* next = block->ssa_env;
+ blocks_.pop_back();
+ ifs_.pop_back();
+ SetEnv("switch:end", next);
} else {
- // Switch case finished.
- if (p->done()) {
- // Last case. Fall through to the end.
- Block* block = &blocks_.back();
- ReduceBreakToExprBlock(p, block);
- SsaEnv* next = block->ssa_env;
- blocks_.pop_back();
- ifs_.pop_back();
- SetEnv("switch:end", next);
- } else {
- // Interior case. Maybe fall through to the next case.
- SsaEnv* next = ifs_.back().case_envs[p->index - 1];
- if (ssa_env_->go()) Goto(ssa_env_, next);
- SetEnv("switch:case", next);
- }
+ // Interior case. Maybe fall through to the next case.
+ SsaEnv* next = ifs_.back().case_envs[p->index - 1];
+ if (p->index > 1 && ssa_env_->go()) Goto(ssa_env_, next);
+ SetEnv("switch:case", next);
}
break;
}
@@ -898,12 +1124,11 @@ class LR_WasmDecoder : public Decoder {
break;
}
case kExprSetLocal: {
- int unused = 0;
- uint32_t index;
- LocalType type = LocalOperand(p->pc(), &index, &unused);
+ LocalIndexOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand));
Tree* val = p->last();
- if (type == val->type) {
- if (build()) ssa_env_->locals[index] = val->node;
+ if (operand.type == val->type) {
+ if (build()) ssa_env_->locals[operand.index] = val->node;
p->tree->node = val->node;
} else {
error(p->pc(), val->pc, "Typecheck failed in SetLocal");
@@ -911,12 +1136,11 @@ class LR_WasmDecoder : public Decoder {
break;
}
case kExprStoreGlobal: {
- int unused = 0;
- uint32_t index;
- LocalType type = GlobalOperand(p->pc(), &index, &unused);
+ GlobalIndexOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand));
Tree* val = p->last();
- if (type == val->type) {
- BUILD(StoreGlobal, index, val->node);
+ if (operand.type == val->type) {
+ BUILD(StoreGlobal, operand.index, val->node);
p->tree->node = val->node;
} else {
error(p->pc(), val->pc, "Typecheck failed in StoreGlobal");
@@ -985,34 +1209,29 @@ class LR_WasmDecoder : public Decoder {
return;
case kExprCallFunction: {
- int len;
- uint32_t index;
- FunctionSig* sig = FunctionSigOperand(p->pc(), &index, &len);
- if (!sig) break;
+ FunctionIndexOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand));
if (p->index > 0) {
- TypeCheckLast(p, sig->GetParam(p->index - 1));
+ TypeCheckLast(p, operand.sig->GetParam(p->index - 1));
}
if (p->done() && build()) {
uint32_t count = p->tree->count + 1;
TFNode** buffer = builder_->Buffer(count);
- FunctionSig* sig = FunctionSigOperand(p->pc(), &index, &len);
- USE(sig);
buffer[0] = nullptr; // reserved for code object.
for (uint32_t i = 1; i < count; i++) {
buffer[i] = p->tree->children[i - 1]->node;
}
- p->tree->node = builder_->CallDirect(index, buffer);
+ p->tree->node = builder_->CallDirect(operand.index, buffer);
}
break;
}
case kExprCallIndirect: {
- int len;
- uint32_t index;
- FunctionSig* sig = SigOperand(p->pc(), &index, &len);
+ SignatureIndexOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand));
if (p->index == 1) {
TypeCheckLast(p, kAstI32);
} else {
- TypeCheckLast(p, sig->GetParam(p->index - 2));
+ TypeCheckLast(p, operand.sig->GetParam(p->index - 2));
}
if (p->done() && build()) {
uint32_t count = p->tree->count;
@@ -1020,7 +1239,24 @@ class LR_WasmDecoder : public Decoder {
for (uint32_t i = 0; i < count; i++) {
buffer[i] = p->tree->children[i]->node;
}
- p->tree->node = builder_->CallIndirect(index, buffer);
+ p->tree->node = builder_->CallIndirect(operand.index, buffer);
+ }
+ break;
+ }
+ case kExprCallImport: {
+ ImportIndexOperand operand(this, p->pc());
+ CHECK(Validate(p->pc(), operand));
+ if (p->index > 0) {
+ TypeCheckLast(p, operand.sig->GetParam(p->index - 1));
+ }
+ if (p->done() && build()) {
+ uint32_t count = p->tree->count + 1;
+ TFNode** buffer = builder_->Buffer(count);
+ buffer[0] = nullptr; // reserved for code object.
+ for (uint32_t i = 1; i < count; i++) {
+ buffer[i] = p->tree->children[i - 1]->node;
+ }
+ p->tree->node = builder_->CallImport(operand.index, buffer);
}
break;
}
@@ -1030,13 +1266,17 @@ class LR_WasmDecoder : public Decoder {
}
void ReduceBreakToExprBlock(Production* p, Block* block) {
+ ReduceBreakToExprBlock(p, block, p->tree->count > 0 ? p->last() : nullptr);
+ }
+
+ void ReduceBreakToExprBlock(Production* p, Block* block, Tree* val) {
if (block->stack_depth < 0) {
// This is the inner loop block, which does not have a value.
Goto(ssa_env_, block->ssa_env);
} else {
// Merge the value into the production for the block.
Production* bp = &stack_[block->stack_depth];
- MergeIntoProduction(bp, block->ssa_env, p->last());
+ MergeIntoProduction(bp, block->ssa_env, val);
}
}
@@ -1045,7 +1285,7 @@ class LR_WasmDecoder : public Decoder {
bool first = target->state == SsaEnv::kUnreachable;
Goto(ssa_env_, target);
- if (expr->type == kAstEnd) return;
+ if (expr == nullptr || expr->type == kAstEnd) return;
if (first) {
// first merge to this environment; set the type and the node.
@@ -1069,11 +1309,9 @@ class LR_WasmDecoder : public Decoder {
DCHECK_EQ(1, p->index);
TypeCheckLast(p, kAstI32); // index
if (build()) {
- int length = 0;
- uint32_t offset = 0;
- MemoryAccessOperand(p->pc(), &length, &offset);
+ MemoryAccessOperand operand(this, p->pc());
p->tree->node =
- builder_->LoadMem(type, mem_type, p->last()->node, offset);
+ builder_->LoadMem(type, mem_type, p->last()->node, operand.offset);
}
}
@@ -1084,11 +1322,10 @@ class LR_WasmDecoder : public Decoder {
DCHECK_EQ(2, p->index);
TypeCheckLast(p, type);
if (build()) {
- int length = 0;
- uint32_t offset = 0;
- MemoryAccessOperand(p->pc(), &length, &offset);
+ MemoryAccessOperand operand(this, p->pc());
TFNode* val = p->tree->children[1]->node;
- builder_->StoreMem(mem_type, p->tree->children[0]->node, offset, val);
+ builder_->StoreMem(mem_type, p->tree->children[0]->node, operand.offset,
+ val);
p->tree->node = val;
}
}
@@ -1111,7 +1348,7 @@ class LR_WasmDecoder : public Decoder {
void SetEnv(const char* reason, SsaEnv* env) {
TRACE(" env = %p, block depth = %d, reason = %s", static_cast<void*>(env),
static_cast<int>(blocks_.size()), reason);
- if (env->control != nullptr && FLAG_trace_wasm_decoder) {
+ if (FLAG_trace_wasm_decoder && env && env->control) {
TRACE(", control = ");
compiler::WasmGraphBuilder::PrintDebugName(env->control);
}
@@ -1286,94 +1523,11 @@ class LR_WasmDecoder : public Decoder {
return result;
}
- // Load an operand at [pc + 1].
- template <typename V>
- V Operand(const byte* pc) {
- if ((limit_ - pc) < static_cast<int>(1 + sizeof(V))) {
- const char* msg = "Expected operand following opcode";
- switch (sizeof(V)) {
- case 1:
- msg = "Expected 1-byte operand following opcode";
- break;
- case 2:
- msg = "Expected 2-byte operand following opcode";
- break;
- case 4:
- msg = "Expected 4-byte operand following opcode";
- break;
- default:
- break;
- }
- error(pc, msg);
- return -1;
- }
- return *reinterpret_cast<const V*>(pc + 1);
- }
-
int EnvironmentCount() {
if (builder_) return static_cast<int>(function_env_->GetLocalCount());
return 0; // if we aren't building a graph, don't bother with SSA renaming.
}
- LocalType LocalOperand(const byte* pc, uint32_t* index, int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->IsValidLocal(*index)) {
- return function_env_->GetLocalType(*index);
- }
- error(pc, "invalid local variable index");
- return kAstStmt;
- }
-
- LocalType GlobalOperand(const byte* pc, uint32_t* index, int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->module->IsValidGlobal(*index)) {
- return WasmOpcodes::LocalTypeFor(
- function_env_->module->GetGlobalType(*index));
- }
- error(pc, "invalid global variable index");
- return kAstStmt;
- }
-
- FunctionSig* FunctionSigOperand(const byte* pc, uint32_t* index,
- int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->module->IsValidFunction(*index)) {
- return function_env_->module->GetFunctionSignature(*index);
- }
- error(pc, "invalid function index");
- return nullptr;
- }
-
- FunctionSig* SigOperand(const byte* pc, uint32_t* index, int* length) {
- *index = UnsignedLEB128Operand(pc, length);
- if (function_env_->module->IsValidSignature(*index)) {
- return function_env_->module->GetSignature(*index);
- }
- error(pc, "invalid signature index");
- return nullptr;
- }
-
- uint32_t UnsignedLEB128Operand(const byte* pc, int* length) {
- uint32_t result = 0;
- ReadUnsignedLEB128ErrorCode error_code =
- ReadUnsignedLEB128Operand(pc + 1, limit_, length, &result);
- if (error_code == kInvalidLEB128) error(pc, "invalid LEB128 varint");
- if (error_code == kMissingLEB128) error(pc, "expected LEB128 varint");
- (*length)++;
- return result;
- }
-
- void MemoryAccessOperand(const byte* pc, int* length, uint32_t* offset) {
- byte bitfield = Operand<uint8_t>(pc);
- if (MemoryAccess::OffsetField::decode(bitfield)) {
- *offset = UnsignedLEB128Operand(pc + 1, length);
- (*length)++; // to account for the memory access byte
- } else {
- *offset = 0;
- *length = 2;
- }
- }
-
virtual void onFirstError() {
limit_ = start_; // Terminate decoding loop.
builder_ = nullptr; // Don't build any more nodes.
@@ -1447,137 +1601,114 @@ ReadUnsignedLEB128ErrorCode ReadUnsignedLEB128Operand(const byte* pc,
const byte* limit,
int* length,
uint32_t* result) {
- *result = 0;
- const byte* ptr = pc;
- const byte* end = pc + 5; // maximum 5 bytes.
- if (end > limit) end = limit;
- int shift = 0;
- byte b = 0;
- while (ptr < end) {
- b = *ptr++;
- *result = *result | ((b & 0x7F) << shift);
- if ((b & 0x80) == 0) break;
- shift += 7;
- }
- DCHECK_LE(ptr - pc, 5);
- *length = static_cast<int>(ptr - pc);
- if (ptr == end && (b & 0x80)) {
- return kInvalidLEB128;
- } else if (*length == 0) {
- return kMissingLEB128;
- } else {
- return kNoError;
- }
+ Decoder decoder(pc, limit);
+ *result = decoder.checked_read_u32v(pc, 0, length);
+ if (decoder.ok()) return kNoError;
+ return (limit - pc) > 1 ? kInvalidLEB128 : kMissingLEB128;
}
+int OpcodeLength(const byte* pc, const byte* end) {
+ WasmDecoder decoder(nullptr, pc, end);
+ return decoder.OpcodeLength(pc);
+}
-int OpcodeLength(const byte* pc) {
- switch (static_cast<WasmOpcode>(*pc)) {
-#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
- FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
- FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
-#undef DECLARE_OPCODE_CASE
+int OpcodeArity(FunctionEnv* env, const byte* pc, const byte* end) {
+ WasmDecoder decoder(env, pc, end);
+ return decoder.OpcodeArity(pc);
+}
- case kExprI8Const:
- case kExprBlock:
- case kExprLoop:
- case kExprBr:
- case kExprBrIf:
- return 2;
- case kExprI32Const:
- case kExprF32Const:
- return 5;
- case kExprI64Const:
- case kExprF64Const:
- return 9;
- case kExprStoreGlobal:
- case kExprSetLocal:
- case kExprLoadGlobal:
- case kExprCallFunction:
- case kExprCallIndirect:
- case kExprGetLocal: {
- int length;
- uint32_t result = 0;
- ReadUnsignedLEB128Operand(pc + 1, pc + 6, &length, &result);
- return 1 + length;
- }
- case kExprTableSwitch: {
- uint16_t table_count = *reinterpret_cast<const uint16_t*>(pc + 3);
- return 5 + table_count * 2;
+void PrintAst(FunctionEnv* env, const byte* start, const byte* end) {
+ WasmDecoder decoder(env, start, end);
+ const byte* pc = start;
+ std::vector<int> arity_stack;
+ while (pc < end) {
+ int arity = decoder.OpcodeArity(pc);
+ size_t length = decoder.OpcodeLength(pc);
+
+ for (auto arity : arity_stack) {
+ printf(" ");
+ USE(arity);
}
- default:
- return 1;
+ WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
+ printf("k%s,", WasmOpcodes::OpcodeName(opcode));
+
+ for (size_t i = 1; i < length; i++) {
+ printf(" 0x%02x,", pc[i]);
+ }
+ pc += length;
+ printf("\n");
+
+ arity_stack.push_back(arity);
+ while (arity_stack.back() == 0) {
+ arity_stack.pop_back();
+ if (arity_stack.empty()) break;
+ arity_stack.back()--;
+ }
}
}
+// Analyzes loop bodies for static assignments to locals, which helps in
+// reducing the number of phis introduced at loop headers.
+class LoopAssignmentAnalyzer : public WasmDecoder {
+ public:
+ LoopAssignmentAnalyzer(Zone* zone, FunctionEnv* function_env) : zone_(zone) {
+ function_env_ = function_env;
+ }
-int OpcodeArity(FunctionEnv* env, const byte* pc) {
-#define DECLARE_ARITY(name, ...) \
- static const LocalType kTypes_##name[] = {__VA_ARGS__}; \
- static const int kArity_##name = \
- static_cast<int>(arraysize(kTypes_##name) - 1);
+ BitVector* Analyze(const byte* pc, const byte* limit) {
+ Decoder::Reset(pc, limit);
+ if (pc_ >= limit_) return nullptr;
+ if (*pc_ != kExprLoop) return nullptr;
- FOREACH_SIGNATURE(DECLARE_ARITY);
-#undef DECLARE_ARITY
+ BitVector* assigned =
+ new (zone_) BitVector(function_env_->total_locals, zone_);
+ // Keep a stack to model the nesting of expressions.
+ std::vector<int> arity_stack;
+ arity_stack.push_back(OpcodeArity(pc_));
+ pc_ += OpcodeLength(pc_);
- switch (static_cast<WasmOpcode>(*pc)) {
- case kExprI8Const:
- case kExprI32Const:
- case kExprI64Const:
- case kExprF64Const:
- case kExprF32Const:
- case kExprGetLocal:
- case kExprLoadGlobal:
- case kExprNop:
- case kExprUnreachable:
- return 0;
+ // Iteratively process all AST nodes nested inside the loop.
+ while (pc_ < limit_) {
+ WasmOpcode opcode = static_cast<WasmOpcode>(*pc_);
+ int arity = 0;
+ int length = 1;
+ if (opcode == kExprSetLocal) {
+ LocalIndexOperand operand(this, pc_);
+ if (assigned->length() > 0 &&
+ static_cast<int>(operand.index) < assigned->length()) {
+ // Unverified code might have an out-of-bounds index.
+ assigned->Add(operand.index);
+ }
+ arity = 1;
+ length = 1 + operand.length;
+ } else {
+ arity = OpcodeArity(pc_);
+ length = OpcodeLength(pc_);
+ }
- case kExprBr:
- case kExprStoreGlobal:
- case kExprSetLocal:
- return 1;
-
- case kExprIf:
- case kExprBrIf:
- return 2;
- case kExprIfElse:
- case kExprSelect:
- return 3;
- case kExprBlock:
- case kExprLoop:
- return *(pc + 1);
-
- case kExprCallFunction: {
- int index = *(pc + 1);
- return static_cast<int>(
- env->module->GetFunctionSignature(index)->parameter_count());
- }
- case kExprCallIndirect: {
- int index = *(pc + 1);
- return 1 + static_cast<int>(
- env->module->GetSignature(index)->parameter_count());
- }
- case kExprReturn:
- return static_cast<int>(env->sig->return_count());
- case kExprTableSwitch: {
- uint16_t case_count = *reinterpret_cast<const uint16_t*>(pc + 1);
- return 1 + case_count;
+ pc_ += length;
+ arity_stack.push_back(arity);
+ while (arity_stack.back() == 0) {
+ arity_stack.pop_back();
+ if (arity_stack.empty()) return assigned; // reached end of loop
+ arity_stack.back()--;
+ }
}
+ return assigned;
+ }
-#define DECLARE_OPCODE_CASE(name, opcode, sig) \
- case kExpr##name: \
- return kArity_##sig;
+ private:
+ Zone* zone_;
+};
- FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
- FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
- FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
- FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
-#undef DECLARE_OPCODE_CASE
- }
- UNREACHABLE();
- return 0;
+
+BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env,
+ const byte* start, const byte* end) {
+ LoopAssignmentAnalyzer analyzer(zone, env);
+ return analyzer.Analyze(start, end);
}
+
} // namespace wasm
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/wasm/ast-decoder.h b/deps/v8/src/wasm/ast-decoder.h
index 5b95ad9f87..465bacaab8 100644
--- a/deps/v8/src/wasm/ast-decoder.h
+++ b/deps/v8/src/wasm/ast-decoder.h
@@ -6,18 +6,181 @@
#define V8_WASM_AST_DECODER_H_
#include "src/signature.h"
+#include "src/wasm/decoder.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"
namespace v8 {
namespace internal {
+class BitVector; // forward declaration
+
namespace compiler { // external declarations from compiler.
class WasmGraphBuilder;
}
namespace wasm {
+// Helpers for decoding different kinds of operands which follow bytecodes.
+struct LocalIndexOperand {
+ uint32_t index;
+ LocalType type;
+ int length;
+
+ inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
+ index = decoder->checked_read_u32v(pc, 1, &length, "local index");
+ type = kAstStmt;
+ }
+};
+
+struct ImmI8Operand {
+ int8_t value;
+ int length;
+ inline ImmI8Operand(Decoder* decoder, const byte* pc) {
+ value = bit_cast<int8_t>(decoder->checked_read_u8(pc, 1, "immi8"));
+ length = 1;
+ }
+};
+
+struct ImmI32Operand {
+ int32_t value;
+ int length;
+ inline ImmI32Operand(Decoder* decoder, const byte* pc) {
+ value = bit_cast<int32_t>(decoder->checked_read_u32(pc, 1, "immi32"));
+ length = 4;
+ }
+};
+
+struct ImmI64Operand {
+ int64_t value;
+ int length;
+ inline ImmI64Operand(Decoder* decoder, const byte* pc) {
+ value = bit_cast<int64_t>(decoder->checked_read_u64(pc, 1, "immi64"));
+ length = 8;
+ }
+};
+
+struct ImmF32Operand {
+ float value;
+ int length;
+ inline ImmF32Operand(Decoder* decoder, const byte* pc) {
+ value = bit_cast<float>(decoder->checked_read_u32(pc, 1, "immf32"));
+ length = 4;
+ }
+};
+
+struct ImmF64Operand {
+ double value;
+ int length;
+ inline ImmF64Operand(Decoder* decoder, const byte* pc) {
+ value = bit_cast<double>(decoder->checked_read_u64(pc, 1, "immf64"));
+ length = 8;
+ }
+};
+
+struct GlobalIndexOperand {
+ uint32_t index;
+ LocalType type;
+ MachineType machine_type;
+ int length;
+
+ inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
+ index = decoder->checked_read_u32v(pc, 1, &length, "global index");
+ type = kAstStmt;
+ machine_type = MachineType::None();
+ }
+};
+
+struct Block;
+struct BreakDepthOperand {
+ uint32_t depth;
+ Block* target;
+ int length;
+ inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
+ depth = decoder->checked_read_u8(pc, 1, "break depth");
+ length = 1;
+ target = nullptr;
+ }
+};
+
+struct BlockCountOperand {
+ uint32_t count;
+ int length;
+ inline BlockCountOperand(Decoder* decoder, const byte* pc) {
+ count = decoder->checked_read_u8(pc, 1, "block count");
+ length = 1;
+ }
+};
+
+struct SignatureIndexOperand {
+ uint32_t index;
+ FunctionSig* sig;
+ int length;
+ inline SignatureIndexOperand(Decoder* decoder, const byte* pc) {
+ index = decoder->checked_read_u32v(pc, 1, &length, "signature index");
+ sig = nullptr;
+ }
+};
+
+struct FunctionIndexOperand {
+ uint32_t index;
+ FunctionSig* sig;
+ int length;
+ inline FunctionIndexOperand(Decoder* decoder, const byte* pc) {
+ index = decoder->checked_read_u32v(pc, 1, &length, "function index");
+ sig = nullptr;
+ }
+};
+
+struct ImportIndexOperand {
+ uint32_t index;
+ FunctionSig* sig;
+ int length;
+ inline ImportIndexOperand(Decoder* decoder, const byte* pc) {
+ index = decoder->checked_read_u32v(pc, 1, &length, "import index");
+ sig = nullptr;
+ }
+};
+
+struct TableSwitchOperand {
+ uint32_t case_count;
+ uint32_t table_count;
+ const byte* table;
+ int length;
+ inline TableSwitchOperand(Decoder* decoder, const byte* pc) {
+ case_count = decoder->checked_read_u16(pc, 1, "expected #cases");
+ table_count = decoder->checked_read_u16(pc, 3, "expected #entries");
+ length = 4 + table_count * 2;
+
+ if (decoder->check(pc, 5, table_count * 2, "expected <table entries>")) {
+ table = pc + 5;
+ } else {
+ table = nullptr;
+ }
+ }
+ inline uint16_t read_entry(Decoder* decoder, int i) {
+ DCHECK(i >= 0 && static_cast<uint32_t>(i) < table_count);
+ return table ? decoder->read_u16(table + i * sizeof(uint16_t)) : 0;
+ }
+};
+
+struct MemoryAccessOperand {
+ bool aligned;
+ uint32_t offset;
+ int length;
+ inline MemoryAccessOperand(Decoder* decoder, const byte* pc) {
+ byte bitfield = decoder->checked_read_u8(pc, 1, "memory access byte");
+ aligned = MemoryAccess::AlignmentField::decode(bitfield);
+ if (MemoryAccess::OffsetField::decode(bitfield)) {
+ offset = decoder->checked_read_u32v(pc, 2, &length, "memory offset");
+ length++;
+ } else {
+ offset = 0;
+ length = 1;
+ }
+ }
+};
+
typedef compiler::WasmGraphBuilder TFBuilder;
struct ModuleEnv; // forward declaration of module interface.
@@ -26,56 +189,55 @@ struct ModuleEnv; // forward declaration of module interface.
struct FunctionEnv {
ModuleEnv* module; // module environment
FunctionSig* sig; // signature of this function
- uint32_t local_int32_count; // number of int32 locals
- uint32_t local_int64_count; // number of int64 locals
- uint32_t local_float32_count; // number of float32 locals
- uint32_t local_float64_count; // number of float64 locals
+ uint32_t local_i32_count; // number of int32 locals
+ uint32_t local_i64_count; // number of int64 locals
+ uint32_t local_f32_count; // number of float32 locals
+ uint32_t local_f64_count; // number of float64 locals
uint32_t total_locals; // sum of parameters and all locals
- bool IsValidLocal(uint32_t index) { return index < total_locals; }
uint32_t GetLocalCount() { return total_locals; }
LocalType GetLocalType(uint32_t index) {
if (index < static_cast<uint32_t>(sig->parameter_count())) {
return sig->GetParam(index);
}
index -= static_cast<uint32_t>(sig->parameter_count());
- if (index < local_int32_count) return kAstI32;
- index -= local_int32_count;
- if (index < local_int64_count) return kAstI64;
- index -= local_int64_count;
- if (index < local_float32_count) return kAstF32;
- index -= local_float32_count;
- if (index < local_float64_count) return kAstF64;
+ if (index < local_i32_count) return kAstI32;
+ index -= local_i32_count;
+ if (index < local_i64_count) return kAstI64;
+ index -= local_i64_count;
+ if (index < local_f32_count) return kAstF32;
+ index -= local_f32_count;
+ if (index < local_f64_count) return kAstF64;
return kAstStmt;
}
void AddLocals(LocalType type, uint32_t count) {
switch (type) {
case kAstI32:
- local_int32_count += count;
+ local_i32_count += count;
break;
case kAstI64:
- local_int64_count += count;
+ local_i64_count += count;
break;
case kAstF32:
- local_float32_count += count;
+ local_f32_count += count;
break;
case kAstF64:
- local_float64_count += count;
+ local_f64_count += count;
break;
default:
UNREACHABLE();
}
total_locals += count;
- DCHECK(total_locals ==
- (sig->parameter_count() + local_int32_count + local_int64_count +
- local_float32_count + local_float64_count));
+ DCHECK_EQ(total_locals,
+ (sig->parameter_count() + local_i32_count + local_i64_count +
+ local_f32_count + local_f64_count));
}
void SumLocals() {
total_locals = static_cast<uint32_t>(sig->parameter_count()) +
- local_int32_count + local_int64_count + local_float32_count +
- local_float64_count;
+ local_i32_count + local_i64_count + local_f32_count +
+ local_f64_count;
}
};
@@ -89,6 +251,8 @@ TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start,
TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, const byte* base,
const byte* start, const byte* end);
+void PrintAst(FunctionEnv* env, const byte* start, const byte* end);
+
inline TreeResult VerifyWasmCode(FunctionEnv* env, const byte* start,
const byte* end) {
return VerifyWasmCode(env, nullptr, start, end);
@@ -104,11 +268,14 @@ enum ReadUnsignedLEB128ErrorCode { kNoError, kInvalidLEB128, kMissingLEB128 };
ReadUnsignedLEB128ErrorCode ReadUnsignedLEB128Operand(const byte*, const byte*,
int*, uint32_t*);
+BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, FunctionEnv* env,
+ const byte* start, const byte* end);
+
// Computes the length of the opcode at the given address.
-int OpcodeLength(const byte* pc);
+int OpcodeLength(const byte* pc, const byte* end);
// Computes the arity (number of sub-nodes) of the opcode at the given address.
-int OpcodeArity(FunctionEnv* env, const byte* pc);
+int OpcodeArity(FunctionEnv* env, const byte* pc, const byte* end);
} // namespace wasm
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/wasm/decoder.h b/deps/v8/src/wasm/decoder.h
index 698919d6a0..0e88eda022 100644
--- a/deps/v8/src/wasm/decoder.h
+++ b/deps/v8/src/wasm/decoder.h
@@ -24,6 +24,12 @@ namespace wasm {
#define TRACE(...)
#endif
+#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
+#define UNALIGNED_ACCESS_OK 1
+#else
+#define UNALIGNED_ACCESS_OK 0
+#endif
+
// A helper utility to decode bytes, integers, fields, varints, etc, from
// a buffer of bytes.
class Decoder {
@@ -32,107 +38,188 @@ class Decoder {
: start_(start),
pc_(start),
limit_(end),
+ end_(end),
error_pc_(nullptr),
error_pt_(nullptr) {}
virtual ~Decoder() {}
+ inline bool check(const byte* base, int offset, int length, const char* msg) {
+ DCHECK_GE(base, start_);
+ if ((base + offset + length) > limit_) {
+ error(base, base + offset, msg);
+ return false;
+ }
+ return true;
+ }
+
+ // Reads a single 8-bit byte, reporting an error if out of bounds.
+ inline uint8_t checked_read_u8(const byte* base, int offset,
+ const char* msg = "expected 1 byte") {
+ return check(base, offset, 1, msg) ? base[offset] : 0;
+ }
+
+ // Reads 16-bit word, reporting an error if out of bounds.
+ inline uint16_t checked_read_u16(const byte* base, int offset,
+ const char* msg = "expected 2 bytes") {
+ return check(base, offset, 2, msg) ? read_u16(base + offset) : 0;
+ }
+
+ // Reads 32-bit word, reporting an error if out of bounds.
+ inline uint32_t checked_read_u32(const byte* base, int offset,
+ const char* msg = "expected 4 bytes") {
+ return check(base, offset, 4, msg) ? read_u32(base + offset) : 0;
+ }
+
+ // Reads 64-bit word, reporting an error if out of bounds.
+ inline uint64_t checked_read_u64(const byte* base, int offset,
+ const char* msg = "expected 8 bytes") {
+ return check(base, offset, 8, msg) ? read_u64(base + offset) : 0;
+ }
+
+ uint32_t checked_read_u32v(const byte* base, int offset, int* length,
+ const char* msg = "expected LEB128") {
+ if (!check(base, offset, 1, msg)) {
+ *length = 0;
+ return 0;
+ }
+
+ const ptrdiff_t kMaxDiff = 5; // maximum 5 bytes.
+ const byte* ptr = base + offset;
+ const byte* end = ptr + kMaxDiff;
+ if (end > limit_) end = limit_;
+ int shift = 0;
+ byte b = 0;
+ uint32_t result = 0;
+ while (ptr < end) {
+ b = *ptr++;
+ result = result | ((b & 0x7F) << shift);
+ if ((b & 0x80) == 0) break;
+ shift += 7;
+ }
+ DCHECK_LE(ptr - (base + offset), kMaxDiff);
+ *length = static_cast<int>(ptr - (base + offset));
+ if (ptr == end && (b & 0x80)) {
+ error(base, ptr, msg);
+ return 0;
+ }
+ return result;
+ }
+
+ // Reads a single 16-bit unsigned integer (little endian).
+ inline uint16_t read_u16(const byte* ptr) {
+ DCHECK(ptr >= start_ && (ptr + 2) <= end_);
+#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
+ return *reinterpret_cast<const uint16_t*>(ptr);
+#else
+ uint16_t b0 = ptr[0];
+ uint16_t b1 = ptr[1];
+ return (b1 << 8) | b0;
+#endif
+ }
+
+ // Reads a single 32-bit unsigned integer (little endian).
+ inline uint32_t read_u32(const byte* ptr) {
+ DCHECK(ptr >= start_ && (ptr + 4) <= end_);
+#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
+ return *reinterpret_cast<const uint32_t*>(ptr);
+#else
+ uint32_t b0 = ptr[0];
+ uint32_t b1 = ptr[1];
+ uint32_t b2 = ptr[2];
+ uint32_t b3 = ptr[3];
+ return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+#endif
+ }
+
+ // Reads a single 64-bit unsigned integer (little endian).
+ inline uint64_t read_u64(const byte* ptr) {
+ DCHECK(ptr >= start_ && (ptr + 8) <= end_);
+#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
+ return *reinterpret_cast<const uint64_t*>(ptr);
+#else
+ uint32_t b0 = ptr[0];
+ uint32_t b1 = ptr[1];
+ uint32_t b2 = ptr[2];
+ uint32_t b3 = ptr[3];
+ uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+ uint32_t b4 = ptr[4];
+ uint32_t b5 = ptr[5];
+ uint32_t b6 = ptr[6];
+ uint32_t b7 = ptr[7];
+ uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
+ return (high << 32) | low;
+#endif
+ }
+
// Reads a 8-bit unsigned integer (byte) and advances {pc_}.
- uint8_t u8(const char* name = nullptr) {
+ uint8_t consume_u8(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint8_t");
if (checkAvailable(1)) {
byte val = *(pc_++);
TRACE("%02x = %d\n", val, val);
return val;
- } else {
- error("expected 1 byte, but fell off end");
- return traceOffEnd<uint8_t>();
}
+ return traceOffEnd<uint8_t>();
}
// Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
- uint16_t u16(const char* name = nullptr) {
+ uint16_t consume_u16(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint16_t");
if (checkAvailable(2)) {
-#ifdef V8_TARGET_LITTLE_ENDIAN
- byte b0 = pc_[0];
- byte b1 = pc_[1];
-#else
- byte b1 = pc_[0];
- byte b0 = pc_[1];
-#endif
- uint16_t val = static_cast<uint16_t>(b1 << 8) | b0;
+ uint16_t val = read_u16(pc_);
TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
pc_ += 2;
return val;
- } else {
- error("expected 2 bytes, but fell off end");
- return traceOffEnd<uint16_t>();
}
+ return traceOffEnd<uint16_t>();
}
// Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
- uint32_t u32(const char* name = nullptr) {
+ uint32_t consume_u32(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint32_t");
if (checkAvailable(4)) {
-#ifdef V8_TARGET_LITTLE_ENDIAN
- byte b0 = pc_[0];
- byte b1 = pc_[1];
- byte b2 = pc_[2];
- byte b3 = pc_[3];
-#else
- byte b3 = pc_[0];
- byte b2 = pc_[1];
- byte b1 = pc_[2];
- byte b0 = pc_[3];
-#endif
- uint32_t val = static_cast<uint32_t>(b3 << 24) |
- static_cast<uint32_t>(b2 << 16) |
- static_cast<uint32_t>(b1 << 8) | b0;
+ uint32_t val = read_u32(pc_);
TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
pc_ += 4;
return val;
- } else {
- error("expected 4 bytes, but fell off end");
- return traceOffEnd<uint32_t>();
}
+ return traceOffEnd<uint32_t>();
}
// Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
- uint32_t u32v(int* length, const char* name = nullptr) {
+ uint32_t consume_u32v(int* length, const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "varint");
- if (!checkAvailable(1)) {
- error("expected at least 1 byte, but fell off end");
- return traceOffEnd<uint32_t>();
- }
-
- const byte* pos = pc_;
- const byte* end = pc_ + 5;
- if (end > limit_) end = limit_;
+ if (checkAvailable(1)) {
+ const byte* pos = pc_;
+ const byte* end = pc_ + 5;
+ if (end > limit_) end = limit_;
- uint32_t result = 0;
- int shift = 0;
- byte b = 0;
- while (pc_ < end) {
- b = *pc_++;
- TRACE("%02x ", b);
- result = result | ((b & 0x7F) << shift);
- if ((b & 0x80) == 0) break;
- shift += 7;
- }
+ uint32_t result = 0;
+ int shift = 0;
+ byte b = 0;
+ while (pc_ < end) {
+ b = *pc_++;
+ TRACE("%02x ", b);
+ result = result | ((b & 0x7F) << shift);
+ if ((b & 0x80) == 0) break;
+ shift += 7;
+ }
- *length = static_cast<int>(pc_ - pos);
- if (pc_ == end && (b & 0x80)) {
- error(pc_ - 1, "varint too large");
- } else {
- TRACE("= %u\n", result);
+ *length = static_cast<int>(pc_ - pos);
+ if (pc_ == end && (b & 0x80)) {
+ error(pc_ - 1, "varint too large");
+ } else {
+ TRACE("= %u\n", result);
+ }
+ return result;
}
- return result;
+ return traceOffEnd<uint32_t>();
}
// Check that at least {size} bytes exist between {pc_} and {limit_}.
@@ -145,6 +232,12 @@ class Decoder {
}
}
+ bool RangeOk(const byte* pc, int length) {
+ if (pc < start_ || pc_ >= limit_) return false;
+ if ((pc + length) >= limit_) return false;
+ return true;
+ }
+
void error(const char* msg) { error(pc_, nullptr, msg); }
void error(const byte* pc, const char* msg) { error(pc, nullptr, msg); }
@@ -208,6 +301,7 @@ class Decoder {
start_ = start;
pc_ = start;
limit_ = end;
+ end_ = end;
error_pc_ = nullptr;
error_pt_ = nullptr;
error_msg_.Reset(nullptr);
@@ -220,6 +314,7 @@ class Decoder {
const byte* start_;
const byte* pc_;
const byte* limit_;
+ const byte* end_;
const byte* error_pc_;
const byte* error_pt_;
base::SmartArrayPointer<char> error_msg_;
diff --git a/deps/v8/src/wasm/encoder.cc b/deps/v8/src/wasm/encoder.cc
index d8d36338b1..d80a275338 100644
--- a/deps/v8/src/wasm/encoder.cc
+++ b/deps/v8/src/wasm/encoder.cc
@@ -30,13 +30,13 @@ void EmitUint8(byte** b, uint8_t x) {
void EmitUint16(byte** b, uint16_t x) {
- Memory::uint16_at(*b) = x;
+ WriteUnalignedUInt16(*b, x);
*b += 2;
}
void EmitUint32(byte** b, uint32_t x) {
- Memory::uint32_at(*b) = x;
+ WriteUnalignedUInt32(*b, x);
*b += 4;
}
@@ -121,12 +121,6 @@ void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
}
-void WasmFunctionBuilder::EmitWithLocal(WasmOpcode opcode) {
- body_.push_back(static_cast<byte>(opcode));
- local_indices_.push_back(static_cast<uint32_t>(body_.size()) - 1);
-}
-
-
uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) {
body_.push_back(immediate);
return static_cast<uint32_t>(body_.size()) - 1;
@@ -202,44 +196,44 @@ WasmFunctionEncoder* WasmFunctionBuilder::Build(Zone* zone,
void WasmFunctionBuilder::IndexVars(WasmFunctionEncoder* e,
uint16_t* var_index) const {
uint16_t param = 0;
- uint16_t int32 = 0;
- uint16_t int64 = 0;
- uint16_t float32 = 0;
- uint16_t float64 = 0;
+ uint16_t i32 = 0;
+ uint16_t i64 = 0;
+ uint16_t f32 = 0;
+ uint16_t f64 = 0;
for (size_t i = 0; i < locals_.size(); i++) {
if (locals_.at(i).param_) {
param++;
} else if (locals_.at(i).type_ == kAstI32) {
- int32++;
+ i32++;
} else if (locals_.at(i).type_ == kAstI64) {
- int64++;
+ i64++;
} else if (locals_.at(i).type_ == kAstF32) {
- float32++;
+ f32++;
} else if (locals_.at(i).type_ == kAstF64) {
- float64++;
+ f64++;
}
}
- e->local_int32_count_ = int32;
- e->local_int64_count_ = int64;
- e->local_float32_count_ = float32;
- e->local_float64_count_ = float64;
- float64 = param + int32 + int64 + float32;
- float32 = param + int32 + int64;
- int64 = param + int32;
- int32 = param;
+ e->local_i32_count_ = i32;
+ e->local_i64_count_ = i64;
+ e->local_f32_count_ = f32;
+ e->local_f64_count_ = f64;
+ f64 = param + i32 + i64 + f32;
+ f32 = param + i32 + i64;
+ i64 = param + i32;
+ i32 = param;
param = 0;
for (size_t i = 0; i < locals_.size(); i++) {
if (locals_.at(i).param_) {
e->params_.push_back(locals_.at(i).type_);
var_index[i] = param++;
} else if (locals_.at(i).type_ == kAstI32) {
- var_index[i] = int32++;
+ var_index[i] = i32++;
} else if (locals_.at(i).type_ == kAstI64) {
- var_index[i] = int64++;
+ var_index[i] = i64++;
} else if (locals_.at(i).type_ == kAstF32) {
- var_index[i] = float32++;
+ var_index[i] = f32++;
} else if (locals_.at(i).type_ == kAstF64) {
- var_index[i] = float64++;
+ var_index[i] = f64++;
}
}
}
@@ -269,7 +263,7 @@ uint32_t WasmFunctionEncoder::BodySize(void) const {
uint32_t WasmFunctionEncoder::NameSize() const {
- return exported_ ? static_cast<uint32_t>(name_.size()) : 0;
+ return HasName() ? static_cast<uint32_t>(name_.size()) : 0;
}
@@ -291,10 +285,10 @@ void WasmFunctionEncoder::Serialize(byte* buffer, byte** header,
}
if (HasLocals()) {
- EmitUint16(header, local_int32_count_);
- EmitUint16(header, local_int64_count_);
- EmitUint16(header, local_float32_count_);
- EmitUint16(header, local_float64_count_);
+ EmitUint16(header, local_i32_count_);
+ EmitUint16(header, local_i64_count_);
+ EmitUint16(header, local_f32_count_);
+ EmitUint16(header, local_f64_count_);
}
if (!external_) {
@@ -370,21 +364,21 @@ void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) {
}
-int WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a,
- FunctionSig* b) const {
- if (a->return_count() < b->return_count()) return -1;
- if (a->return_count() > b->return_count()) return 1;
- if (a->parameter_count() < b->parameter_count()) return -1;
- if (a->parameter_count() > b->parameter_count()) return 1;
+bool WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a,
+ FunctionSig* b) const {
+ if (a->return_count() < b->return_count()) return true;
+ if (a->return_count() > b->return_count()) return false;
+ if (a->parameter_count() < b->parameter_count()) return true;
+ if (a->parameter_count() > b->parameter_count()) return false;
for (size_t r = 0; r < a->return_count(); r++) {
- if (a->GetReturn(r) < b->GetReturn(r)) return -1;
- if (a->GetReturn(r) > b->GetReturn(r)) return 1;
+ if (a->GetReturn(r) < b->GetReturn(r)) return true;
+ if (a->GetReturn(r) > b->GetReturn(r)) return false;
}
for (size_t p = 0; p < a->parameter_count(); p++) {
- if (a->GetParam(p) < b->GetParam(p)) return -1;
- if (a->GetParam(p) > b->GetParam(p)) return 1;
+ if (a->GetParam(p) < b->GetParam(p)) return true;
+ if (a->GetParam(p) > b->GetParam(p)) return false;
}
- return 0;
+ return false;
}
diff --git a/deps/v8/src/wasm/encoder.h b/deps/v8/src/wasm/encoder.h
index f0fabe998a..7b651bf95e 100644
--- a/deps/v8/src/wasm/encoder.h
+++ b/deps/v8/src/wasm/encoder.h
@@ -33,21 +33,21 @@ class WasmFunctionEncoder : public ZoneObject {
friend class WasmFunctionBuilder;
uint16_t signature_index_;
ZoneVector<LocalType> params_;
- uint16_t local_int32_count_;
- uint16_t local_int64_count_;
- uint16_t local_float32_count_;
- uint16_t local_float64_count_;
+ uint16_t local_i32_count_;
+ uint16_t local_i64_count_;
+ uint16_t local_f32_count_;
+ uint16_t local_f64_count_;
bool exported_;
bool external_;
ZoneVector<uint8_t> body_;
ZoneVector<char> name_;
bool HasLocals() const {
- return (local_int32_count_ + local_int64_count_ + local_float32_count_ +
- local_float64_count_) > 0;
+ return (local_i32_count_ + local_i64_count_ + local_f32_count_ +
+ local_f64_count_) > 0;
}
- bool HasName() const { return exported_ && name_.size() > 0; }
+ bool HasName() const { return (exported_ || external_) && name_.size() > 0; }
};
class WasmFunctionBuilder : public ZoneObject {
@@ -60,7 +60,6 @@ class WasmFunctionBuilder : public ZoneObject {
const uint32_t* local_indices, uint32_t indices_size);
void Emit(WasmOpcode opcode);
void EmitWithU8(WasmOpcode opcode, const byte immediate);
- void EmitWithLocal(WasmOpcode opcode);
uint32_t EmitEditableImmediate(const byte immediate);
void EditImmediate(uint32_t offset, const byte immediate);
void Exported(uint8_t flag);
@@ -134,12 +133,12 @@ class WasmModuleBuilder : public ZoneObject {
void AddIndirectFunction(uint16_t index);
WasmModuleWriter* Build(Zone* zone);
- private:
struct CompareFunctionSigs {
- int operator()(FunctionSig* a, FunctionSig* b) const;
+ bool operator()(FunctionSig* a, FunctionSig* b) const;
};
typedef ZoneMap<FunctionSig*, uint16_t, CompareFunctionSigs> SignatureMap;
+ private:
Zone* zone_;
ZoneVector<FunctionSig*> signatures_;
ZoneVector<WasmFunctionBuilder*> functions_;
diff --git a/deps/v8/src/wasm/module-decoder.cc b/deps/v8/src/wasm/module-decoder.cc
index 24f39822f9..62b000da2b 100644
--- a/deps/v8/src/wasm/module-decoder.cc
+++ b/deps/v8/src/wasm/module-decoder.cc
@@ -54,6 +54,7 @@ class ModuleDecoder : public Decoder {
module->functions = new std::vector<WasmFunction>();
module->data_segments = new std::vector<WasmDataSegment>();
module->function_table = new std::vector<uint16_t>();
+ module->import_table = new std::vector<WasmImport>();
bool sections[kMaxModuleSectionCode];
memset(sections, 0, sizeof(sections));
@@ -62,7 +63,7 @@ class ModuleDecoder : public Decoder {
while (pc_ < limit_) {
TRACE("DecodeSection\n");
WasmSectionDeclCode section =
- static_cast<WasmSectionDeclCode>(u8("section"));
+ static_cast<WasmSectionDeclCode>(consume_u8("section"));
// Each section should appear at most once.
if (section < kMaxModuleSectionCode) {
CheckForPreviousSection(sections, section, false);
@@ -75,20 +76,20 @@ class ModuleDecoder : public Decoder {
limit_ = pc_;
break;
case kDeclMemory:
- module->min_mem_size_log2 = u8("min memory");
- module->max_mem_size_log2 = u8("max memory");
- module->mem_export = u8("export memory") != 0;
+ module->min_mem_size_log2 = consume_u8("min memory");
+ module->max_mem_size_log2 = consume_u8("max memory");
+ module->mem_export = consume_u8("export memory") != 0;
break;
case kDeclSignatures: {
int length;
- uint32_t signatures_count = u32v(&length, "signatures count");
+ uint32_t signatures_count = consume_u32v(&length, "signatures count");
module->signatures->reserve(SafeReserve(signatures_count));
// Decode signatures.
for (uint32_t i = 0; i < signatures_count; i++) {
if (failed()) break;
TRACE("DecodeSignature[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
- FunctionSig* s = sig(); // read function sig.
+ FunctionSig* s = consume_sig(); // read function sig.
module->signatures->push_back(s);
}
break;
@@ -97,15 +98,12 @@ class ModuleDecoder : public Decoder {
// Functions require a signature table first.
CheckForPreviousSection(sections, kDeclSignatures, true);
int length;
- uint32_t functions_count = u32v(&length, "functions count");
+ uint32_t functions_count = consume_u32v(&length, "functions count");
module->functions->reserve(SafeReserve(functions_count));
// Set up module environment for verification.
ModuleEnv menv;
menv.module = module;
- menv.globals_area = 0;
- menv.mem_start = 0;
- menv.mem_end = 0;
- menv.function_code = nullptr;
+ menv.instance = nullptr;
menv.asm_js = asm_js_;
// Decode functions.
for (uint32_t i = 0; i < functions_count; i++) {
@@ -114,7 +112,7 @@ class ModuleDecoder : public Decoder {
static_cast<int>(pc_ - start_));
module->functions->push_back(
- {nullptr, 0, 0, 0, 0, 0, 0, false, false});
+ {nullptr, i, 0, 0, 0, 0, 0, 0, false, false});
WasmFunction* function = &module->functions->back();
DecodeFunctionInModule(module, function, false);
}
@@ -133,7 +131,7 @@ class ModuleDecoder : public Decoder {
}
case kDeclGlobals: {
int length;
- uint32_t globals_count = u32v(&length, "globals count");
+ uint32_t globals_count = consume_u32v(&length, "globals count");
module->globals->reserve(SafeReserve(globals_count));
// Decode globals.
for (uint32_t i = 0; i < globals_count; i++) {
@@ -148,7 +146,8 @@ class ModuleDecoder : public Decoder {
}
case kDeclDataSegments: {
int length;
- uint32_t data_segments_count = u32v(&length, "data segments count");
+ uint32_t data_segments_count =
+ consume_u32v(&length, "data segments count");
module->data_segments->reserve(SafeReserve(data_segments_count));
// Decode data segments.
for (uint32_t i = 0; i < data_segments_count; i++) {
@@ -157,7 +156,7 @@ class ModuleDecoder : public Decoder {
static_cast<int>(pc_ - start_));
module->data_segments->push_back({0, 0, 0});
WasmDataSegment* segment = &module->data_segments->back();
- DecodeDataSegmentInModule(segment);
+ DecodeDataSegmentInModule(module, segment);
}
break;
}
@@ -165,14 +164,15 @@ class ModuleDecoder : public Decoder {
// An indirect function table requires functions first.
CheckForPreviousSection(sections, kDeclFunctions, true);
int length;
- uint32_t function_table_count = u32v(&length, "function table count");
+ uint32_t function_table_count =
+ consume_u32v(&length, "function table count");
module->function_table->reserve(SafeReserve(function_table_count));
// Decode function table.
for (uint32_t i = 0; i < function_table_count; i++) {
if (failed()) break;
TRACE("DecodeFunctionTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
- uint16_t index = u16();
+ uint16_t index = consume_u16();
if (index >= module->functions->size()) {
error(pc_ - 2, "invalid function index");
break;
@@ -181,13 +181,66 @@ class ModuleDecoder : public Decoder {
}
break;
}
+ case kDeclStartFunction: {
+ // Declares a start function for a module.
+ CheckForPreviousSection(sections, kDeclFunctions, true);
+ if (module->start_function_index >= 0) {
+ error("start function already declared");
+ break;
+ }
+ int length;
+ const byte* before = pc_;
+ uint32_t index = consume_u32v(&length, "start function index");
+ if (index >= module->functions->size()) {
+ error(before, "invalid start function index");
+ break;
+ }
+ module->start_function_index = static_cast<int>(index);
+ FunctionSig* sig =
+ module->signatures->at(module->functions->at(index).sig_index);
+ if (sig->parameter_count() > 0) {
+ error(before, "invalid start function: non-zero parameter count");
+ break;
+ }
+ break;
+ }
+ case kDeclImportTable: {
+ // Declares an import table.
+ CheckForPreviousSection(sections, kDeclSignatures, true);
+ int length;
+ uint32_t import_table_count =
+ consume_u32v(&length, "import table count");
+ module->import_table->reserve(SafeReserve(import_table_count));
+ // Decode import table.
+ for (uint32_t i = 0; i < import_table_count; i++) {
+ if (failed()) break;
+ TRACE("DecodeImportTable[%d] module+%d\n", i,
+ static_cast<int>(pc_ - start_));
+
+ module->import_table->push_back({nullptr, 0, 0});
+ WasmImport* import = &module->import_table->back();
+
+ const byte* sigpos = pc_;
+ import->sig_index = consume_u16("signature index");
+
+ if (import->sig_index >= module->signatures->size()) {
+ error(sigpos, "invalid signature index");
+ } else {
+ import->sig = module->signatures->at(import->sig_index);
+ }
+ import->module_name_offset = consume_string("import module name");
+ import->function_name_offset =
+ consume_string("import function name");
+ }
+ break;
+ }
case kDeclWLL: {
// Reserved for experimentation by the Web Low-level Language project
// which is augmenting the binary encoding with source code meta
// information. This section does not affect the semantics of the code
// and can be ignored by the runtime. https://github.com/JSStats/wll
int length = 0;
- uint32_t section_size = u32v(&length, "section size");
+ uint32_t section_size = consume_u32v(&length, "section size");
if (pc_ + section_size > limit_ || pc_ + section_size < pc_) {
error(pc_ - length, "invalid section size");
break;
@@ -249,14 +302,14 @@ class ModuleDecoder : public Decoder {
FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
WasmFunction* function) {
pc_ = start_;
- function->sig = sig(); // read signature
+ function->sig = consume_sig(); // read signature
function->name_offset = 0; // ---- name
function->code_start_offset = off(pc_ + 8); // ---- code start
function->code_end_offset = off(limit_); // ---- code end
- function->local_int32_count = u16(); // read u16
- function->local_int64_count = u16(); // read u16
- function->local_float32_count = u16(); // read u16
- function->local_float64_count = u16(); // read u16
+ function->local_i32_count = consume_u16(); // read u16
+ function->local_i64_count = consume_u16(); // read u16
+ function->local_f32_count = consume_u16(); // read u16
+ function->local_f64_count = consume_u16(); // read u16
function->exported = false; // ---- exported
function->external = false; // ---- external
@@ -271,7 +324,7 @@ class ModuleDecoder : public Decoder {
// Decodes a single function signature at {start}.
FunctionSig* DecodeFunctionSignature(const byte* start) {
pc_ = start;
- FunctionSig* result = sig();
+ FunctionSig* result = consume_sig();
return ok() ? result : nullptr;
}
@@ -284,19 +337,19 @@ class ModuleDecoder : public Decoder {
// Decodes a single global entry inside a module starting at {pc_}.
void DecodeGlobalInModule(WasmGlobal* global) {
- global->name_offset = string("global name");
+ global->name_offset = consume_string("global name");
global->type = mem_type();
global->offset = 0;
- global->exported = u8("exported") != 0;
+ global->exported = consume_u8("exported") != 0;
}
// Decodes a single function entry inside a module starting at {pc_}.
void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
bool verify_body = true) {
- byte decl_bits = u8("function decl");
+ byte decl_bits = consume_u8("function decl");
const byte* sigpos = pc_;
- function->sig_index = u16("signature index");
+ function->sig_index = consume_u16("signature index");
if (function->sig_index >= module->signatures->size()) {
return error(sigpos, "invalid signature index");
@@ -313,7 +366,7 @@ class ModuleDecoder : public Decoder {
(decl_bits & kDeclFunctionImport) == 0 ? " body" : "");
if (decl_bits & kDeclFunctionName) {
- function->name_offset = string("function name");
+ function->name_offset = consume_string("function name");
}
function->exported = decl_bits & kDeclFunctionExport;
@@ -325,13 +378,13 @@ class ModuleDecoder : public Decoder {
}
if (decl_bits & kDeclFunctionLocals) {
- function->local_int32_count = u16("int32 count");
- function->local_int64_count = u16("int64 count");
- function->local_float32_count = u16("float32 count");
- function->local_float64_count = u16("float64 count");
+ function->local_i32_count = consume_u16("i32 count");
+ function->local_i64_count = consume_u16("i64 count");
+ function->local_f32_count = consume_u16("f32 count");
+ function->local_f64_count = consume_u16("f64 count");
}
- uint16_t size = u16("body size");
+ uint16_t size = consume_u16("body size");
if (ok()) {
if ((pc_ + size) > limit_) {
return error(pc_, limit_,
@@ -345,35 +398,51 @@ class ModuleDecoder : public Decoder {
}
}
+ bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) {
+ if (offset > limit) return false;
+ if ((offset + size) < offset) return false; // overflow
+ return (offset + size) <= limit;
+ }
+
// Decodes a single data segment entry inside a module starting at {pc_}.
- void DecodeDataSegmentInModule(WasmDataSegment* segment) {
- segment->dest_addr =
- u32("destination"); // TODO(titzer): check it's within the memory size.
- segment->source_offset = offset("source offset");
- segment->source_size =
- u32("source size"); // TODO(titzer): check the size is reasonable.
- segment->init = u8("init");
+ void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
+ segment->dest_addr = consume_u32("destination");
+ segment->source_offset = consume_offset("source offset");
+ segment->source_size = consume_u32("source size");
+ segment->init = consume_u8("init");
+
+ // Validate the data is in the module.
+ uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
+ if (!IsWithinLimit(module_limit, segment->source_offset,
+ segment->source_size)) {
+ error(pc_ - sizeof(uint32_t), "segment out of bounds of module");
+ }
+
+ // Validate that the segment will fit into the (minimum) memory.
+ uint32_t memory_limit =
+ 1 << (module ? module->min_mem_size_log2 : WasmModule::kMaxMemSize);
+ if (!IsWithinLimit(memory_limit, segment->dest_addr,
+ segment->source_size)) {
+ error(pc_ - sizeof(uint32_t), "segment out of bounds of memory");
+ }
}
// Verifies the body (code) of a given function.
void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
WasmFunction* function) {
if (FLAG_trace_wasm_decode_time) {
- // TODO(titzer): clean me up a bit.
OFStream os(stdout);
- os << "Verifying WASM function:";
- if (function->name_offset > 0) {
- os << menv->module->GetName(function->name_offset);
- }
+ os << "Verifying WASM function " << WasmFunctionName(function, menv)
+ << std::endl;
os << std::endl;
}
FunctionEnv fenv;
fenv.module = menv;
fenv.sig = function->sig;
- fenv.local_int32_count = function->local_int32_count;
- fenv.local_int64_count = function->local_int64_count;
- fenv.local_float32_count = function->local_float32_count;
- fenv.local_float64_count = function->local_float64_count;
+ fenv.local_i32_count = function->local_i32_count;
+ fenv.local_i64_count = function->local_i64_count;
+ fenv.local_f32_count = function->local_f32_count;
+ fenv.local_f64_count = function->local_f64_count;
fenv.SumLocals();
TreeResult result =
@@ -382,8 +451,7 @@ class ModuleDecoder : public Decoder {
if (result.failed()) {
// Wrap the error message from the function decoder.
std::ostringstream str;
- str << "in function #" << func_num << ": ";
- // TODO(titzer): add function name for the user?
+ str << "in function " << WasmFunctionName(function, menv) << ": ";
str << result;
std::string strval = str.str();
const char* raw = strval.c_str();
@@ -400,8 +468,8 @@ class ModuleDecoder : public Decoder {
// Reads a single 32-bit unsigned integer interpreted as an offset, checking
// the offset is within bounds and advances.
- uint32_t offset(const char* name = nullptr) {
- uint32_t offset = u32(name ? name : "offset");
+ uint32_t consume_offset(const char* name = nullptr) {
+ uint32_t offset = consume_u32(name ? name : "offset");
if (offset > static_cast<uint32_t>(limit_ - start_)) {
error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
}
@@ -410,13 +478,14 @@ class ModuleDecoder : public Decoder {
// Reads a single 32-bit unsigned integer interpreted as an offset into the
// data and validating the string there and advances.
- uint32_t string(const char* name = nullptr) {
- return offset(name ? name : "string"); // TODO(titzer): validate string
+ uint32_t consume_string(const char* name = nullptr) {
+ // TODO(titzer): validate string
+ return consume_offset(name ? name : "string");
}
// Reads a single 8-bit integer, interpreting it as a local type.
- LocalType local_type() {
- byte val = u8("local type");
+ LocalType consume_local_type() {
+ byte val = consume_u8("local type");
LocalTypeCode t = static_cast<LocalTypeCode>(val);
switch (t) {
case kLocalVoid:
@@ -437,7 +506,7 @@ class ModuleDecoder : public Decoder {
// Reads a single 8-bit integer, interpreting it as a memory type.
MachineType mem_type() {
- byte val = u8("memory type");
+ byte val = consume_u8("memory type");
MemTypeCode t = static_cast<MemTypeCode>(val);
switch (t) {
case kMemI8:
@@ -467,14 +536,14 @@ class ModuleDecoder : public Decoder {
}
// Parses an inline function signature.
- FunctionSig* sig() {
- byte count = u8("param count");
- LocalType ret = local_type();
+ FunctionSig* consume_sig() {
+ byte count = consume_u8("param count");
+ LocalType ret = consume_local_type();
FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
if (ret != kAstStmt) builder.AddReturn(ret);
for (int i = 0; i < count; i++) {
- LocalType param = local_type();
+ LocalType param = consume_local_type();
if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
builder.AddParam(param);
}
diff --git a/deps/v8/src/wasm/wasm-js.cc b/deps/v8/src/wasm/wasm-js.cc
index 80d8bdb236..62a2676032 100644
--- a/deps/v8/src/wasm/wasm-js.cc
+++ b/deps/v8/src/wasm/wasm-js.cc
@@ -37,6 +37,7 @@ struct RawBuffer {
RawBuffer GetRawBufferArgument(
ErrorThrower& thrower, const v8::FunctionCallbackInfo<v8::Value>& args) {
+ // TODO(titzer): allow typed array views.
if (args.Length() < 1 || !args[0]->IsArrayBuffer()) {
thrower.Error("Argument 0 must be an array buffer");
return {nullptr, nullptr};
@@ -44,8 +45,6 @@ RawBuffer GetRawBufferArgument(
Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(args[0]);
ArrayBuffer::Contents contents = buffer->GetContents();
- // TODO(titzer): allow offsets into buffers, views, etc.
-
const byte* start = reinterpret_cast<const byte*>(contents.Data());
const byte* end = start + contents.ByteLength();
@@ -100,33 +99,8 @@ void VerifyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (result.val) delete result.val;
}
-
-void CompileRun(const v8::FunctionCallbackInfo<v8::Value>& args) {
- HandleScope scope(args.GetIsolate());
- i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
- ErrorThrower thrower(isolate, "WASM.compileRun()");
-
- RawBuffer buffer = GetRawBufferArgument(thrower, args);
- if (thrower.error()) return;
-
- // Decode and pre-verify the functions before compiling and running.
- i::Zone zone;
- internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
- isolate, &zone, buffer.start, buffer.end, true, false);
-
- if (result.failed()) {
- thrower.Failed("", result);
- } else {
- // Success. Compile and run!
- int32_t retval = i::wasm::CompileAndRunWasmModule(isolate, result.val);
- args.GetReturnValue().Set(retval);
- }
-
- if (result.val) delete result.val;
-}
-
-
-v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(i::ParseInfo* info) {
+v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
+ i::ParseInfo* info, i::Handle<i::Object> foreign, ErrorThrower* thrower) {
info->set_global();
info->set_lazy(false);
info->set_allow_lazy_parsing(false);
@@ -141,61 +115,79 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(i::ParseInfo* info) {
v8::internal::AsmTyper typer(info->isolate(), info->zone(), *(info->script()),
info->literal());
+ if (i::FLAG_enable_simd_asmjs) {
+ typer.set_allow_simd(true);
+ }
if (!typer.Validate()) {
+ thrower->Error("Asm.js validation failed: %s", typer.error_message());
return nullptr;
}
auto module = v8::internal::wasm::AsmWasmBuilder(
- info->isolate(), info->zone(), info->literal())
+ info->isolate(), info->zone(), info->literal(), foreign)
.Run();
+
+ if (i::FLAG_dump_asmjs_wasm) {
+ FILE* wasm_file = fopen(i::FLAG_asmjs_wasm_dumpfile, "wb");
+ if (wasm_file) {
+ fwrite(module->Begin(), module->End() - module->Begin(), 1, wasm_file);
+ fclose(wasm_file);
+ }
+ }
+
return module;
}
-void AsmCompileRun(const v8::FunctionCallbackInfo<v8::Value>& args) {
- HandleScope scope(args.GetIsolate());
+void InstantiateModuleCommon(const v8::FunctionCallbackInfo<v8::Value>& args,
+ const byte* start, const byte* end,
+ ErrorThrower* thrower, bool must_decode) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
- ErrorThrower thrower(isolate, "WASM.asmCompileRun()");
- if (args.Length() != 1) {
- thrower.Error("Invalid argument count");
- return;
- }
- if (!args[0]->IsString()) {
- thrower.Error("Invalid argument count");
- return;
+ i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
+ if (args.Length() > 2 && args[2]->IsArrayBuffer()) {
+ Local<Object> obj = Local<Object>::Cast(args[2]);
+ i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj);
+ memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj));
}
- i::Factory* factory = isolate->factory();
+ // Decode but avoid a redundant pass over function bodies for verification.
+ // Verification will happen during compilation.
i::Zone zone;
- Local<String> source = Local<String>::Cast(args[0]);
- i::Handle<i::Script> script = factory->NewScript(Utils::OpenHandle(*source));
- i::ParseInfo info(&zone, script);
+ internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
+ isolate, &zone, start, end, false, false);
- auto module = TranslateAsmModule(&info);
- if (module == nullptr) {
- thrower.Error("Asm.js validation failed");
- return;
+ if (result.failed() && must_decode) {
+ thrower->Error("Asm.js converted module failed to decode");
+ } else if (result.failed()) {
+ thrower->Failed("", result);
+ } else {
+ // Success. Instantiate the module and return the object.
+ i::Handle<i::JSObject> ffi = i::Handle<i::JSObject>::null();
+ if (args.Length() > 1 && args[1]->IsObject()) {
+ Local<Object> obj = Local<Object>::Cast(args[1]);
+ ffi = i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
+ }
+
+ i::MaybeHandle<i::JSObject> object =
+ result.val->Instantiate(isolate, ffi, memory);
+
+ if (!object.is_null()) {
+ args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
+ }
}
- int32_t result = v8::internal::wasm::CompileAndRunWasmModule(
- isolate, module->Begin(), module->End(), true);
- args.GetReturnValue().Set(result);
+ if (result.val) delete result.val;
}
-// TODO(aseemgarg): deal with arraybuffer and foreign functions
void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(args.GetIsolate());
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
ErrorThrower thrower(isolate, "WASM.instantiateModuleFromAsm()");
- if (args.Length() != 1) {
- thrower.Error("Invalid argument count");
- return;
- }
if (!args[0]->IsString()) {
- thrower.Error("Invalid argument count");
+ thrower.Error("Asm module text should be a string");
return;
}
@@ -205,31 +197,18 @@ void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::Script> script = factory->NewScript(Utils::OpenHandle(*source));
i::ParseInfo info(&zone, script);
- auto module = TranslateAsmModule(&info);
- if (module == nullptr) {
- thrower.Error("Asm.js validation failed");
- return;
+ i::Handle<i::Object> foreign;
+ if (args.Length() > 1 && args[1]->IsObject()) {
+ Local<Object> local_foreign = Local<Object>::Cast(args[1]);
+ foreign = v8::Utils::OpenHandle(*local_foreign);
}
- i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
- internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
- isolate, &zone, module->Begin(), module->End(), false, false);
-
- if (result.failed()) {
- thrower.Failed("", result);
- } else {
- // Success. Instantiate the module and return the object.
- i::Handle<i::JSObject> ffi = i::Handle<i::JSObject>::null();
-
- i::MaybeHandle<i::JSObject> object =
- result.val->Instantiate(isolate, ffi, memory);
-
- if (!object.is_null()) {
- args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
- }
+ auto module = TranslateAsmModule(&info, foreign, &thrower);
+ if (module == nullptr) {
+ return;
}
- if (result.val) delete result.val;
+ InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower, true);
}
@@ -241,38 +220,7 @@ void InstantiateModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
RawBuffer buffer = GetRawBufferArgument(thrower, args);
if (buffer.start == nullptr) return;
- i::Handle<i::JSArrayBuffer> memory = i::Handle<i::JSArrayBuffer>::null();
- if (args.Length() > 2 && args[2]->IsArrayBuffer()) {
- Local<Object> obj = Local<Object>::Cast(args[2]);
- i::Handle<i::Object> mem_obj = v8::Utils::OpenHandle(*obj);
- memory = i::Handle<i::JSArrayBuffer>(i::JSArrayBuffer::cast(*mem_obj));
- }
-
- // Decode but avoid a redundant pass over function bodies for verification.
- // Verification will happen during compilation.
- i::Zone zone;
- internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule(
- isolate, &zone, buffer.start, buffer.end, false, false);
-
- if (result.failed()) {
- thrower.Failed("", result);
- } else {
- // Success. Instantiate the module and return the object.
- i::Handle<i::JSObject> ffi = i::Handle<i::JSObject>::null();
- if (args.Length() > 1 && args[1]->IsObject()) {
- Local<Object> obj = Local<Object>::Cast(args[1]);
- ffi = i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
- }
-
- i::MaybeHandle<i::JSObject> object =
- result.val->Instantiate(isolate, ffi, memory);
-
- if (!object.is_null()) {
- args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked()));
- }
- }
-
- if (result.val) delete result.val;
+ InstantiateModuleCommon(args, buffer.start, buffer.end, &thrower, false);
}
} // namespace
@@ -322,11 +270,9 @@ void WasmJs::Install(Isolate* isolate, Handle<JSGlobalObject> global) {
JSObject::AddProperty(global, name, wasm_object, attributes);
// Install functions on the WASM object.
- InstallFunc(isolate, wasm_object, "instantiateModule", InstantiateModule);
InstallFunc(isolate, wasm_object, "verifyModule", VerifyModule);
InstallFunc(isolate, wasm_object, "verifyFunction", VerifyFunction);
- InstallFunc(isolate, wasm_object, "compileRun", CompileRun);
- InstallFunc(isolate, wasm_object, "asmCompileRun", AsmCompileRun);
+ InstallFunc(isolate, wasm_object, "instantiateModule", InstantiateModule);
InstallFunc(isolate, wasm_object, "instantiateModuleFromAsm",
InstantiateModuleFromAsm);
}
diff --git a/deps/v8/src/wasm/wasm-macro-gen.h b/deps/v8/src/wasm/wasm-macro-gen.h
index 470804a73d..dd653c1740 100644
--- a/deps/v8/src/wasm/wasm-macro-gen.h
+++ b/deps/v8/src/wasm/wasm-macro-gen.h
@@ -22,10 +22,10 @@
#define WASM_SELECT(cond, tval, fval) kExprSelect, cond, tval, fval
#define WASM_BR(depth) kExprBr, static_cast<byte>(depth), kExprNop
#define WASM_BR_IF(depth, cond) \
- kExprBrIf, static_cast<byte>(depth), cond, kExprNop
+ kExprBrIf, static_cast<byte>(depth), kExprNop, cond
#define WASM_BRV(depth, val) kExprBr, static_cast<byte>(depth), val
-#define WASM_BRV_IF(depth, cond, val) \
- kExprBrIf, static_cast<byte>(depth), cond, val
+#define WASM_BRV_IF(depth, val, cond) \
+ kExprBrIf, static_cast<byte>(depth), val, cond
#define WASM_BREAK(depth) kExprBr, static_cast<byte>(depth + 1), kExprNop
#define WASM_CONTINUE(depth) kExprBr, static_cast<byte>(depth), kExprNop
#define WASM_BREAKV(depth, val) kExprBr, static_cast<byte>(depth + 1), val
@@ -104,9 +104,12 @@
static_cast<byte>(offset), index, val
#define WASM_CALL_FUNCTION(index, ...) \
kExprCallFunction, static_cast<byte>(index), __VA_ARGS__
+#define WASM_CALL_IMPORT(index, ...) \
+ kExprCallImport, static_cast<byte>(index), __VA_ARGS__
#define WASM_CALL_INDIRECT(index, func, ...) \
kExprCallIndirect, static_cast<byte>(index), func, __VA_ARGS__
#define WASM_CALL_FUNCTION0(index) kExprCallFunction, static_cast<byte>(index)
+#define WASM_CALL_IMPORT0(index) kExprCallImport, static_cast<byte>(index)
#define WASM_CALL_INDIRECT0(index, func) \
kExprCallIndirect, static_cast<byte>(index), func
#define WASM_NOT(x) kExprBoolNot, x
diff --git a/deps/v8/src/wasm/wasm-module.cc b/deps/v8/src/wasm/wasm-module.cc
index fd2428080b..02d197c547 100644
--- a/deps/v8/src/wasm/wasm-module.cc
+++ b/deps/v8/src/wasm/wasm-module.cc
@@ -31,33 +31,32 @@ std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
std::ostream& operator<<(std::ostream& os, const WasmFunction& function) {
- os << "WASM function with signature ";
+ os << "WASM function with signature " << *function.sig;
- // TODO(titzer): factor out rendering of signatures.
- if (function.sig->return_count() == 0) os << "v";
- for (size_t i = 0; i < function.sig->return_count(); i++) {
- os << WasmOpcodes::ShortNameOf(function.sig->GetReturn(i));
- }
- os << "_";
- if (function.sig->parameter_count() == 0) os << "v";
- for (size_t i = 0; i < function.sig->parameter_count(); i++) {
- os << WasmOpcodes::ShortNameOf(function.sig->GetParam(i));
- }
os << " locals: ";
- if (function.local_int32_count)
- os << function.local_int32_count << " int32s ";
- if (function.local_int64_count)
- os << function.local_int64_count << " int64s ";
- if (function.local_float32_count)
- os << function.local_float32_count << " float32s ";
- if (function.local_float64_count)
- os << function.local_float64_count << " float64s ";
+ if (function.local_i32_count) os << function.local_i32_count << " i32s ";
+ if (function.local_i64_count) os << function.local_i64_count << " i64s ";
+ if (function.local_f32_count) os << function.local_f32_count << " f32s ";
+ if (function.local_f64_count) os << function.local_f64_count << " f64s ";
os << " code bytes: "
<< (function.code_end_offset - function.code_start_offset);
return os;
}
+std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) {
+ os << "#" << pair.function_->func_index << ":";
+ if (pair.function_->name_offset > 0) {
+ if (pair.module_) {
+ os << pair.module_->GetName(pair.function_->name_offset);
+ } else {
+ os << "+" << pair.function_->func_index;
+ }
+ } else {
+ os << "?";
+ }
+ return os;
+}
// A helper class for compiling multiple wasm functions that offers
// placeholder code objects for calling functions that are not yet compiled.
@@ -193,35 +192,98 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) {
return fixed;
}
-
-Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, int size,
+Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
byte** backing_store) {
- void* memory = isolate->array_buffer_allocator()->Allocate(size);
- if (!memory) return Handle<JSArrayBuffer>::null();
+ if (size > (1 << WasmModule::kMaxMemSize)) {
+ // TODO(titzer): lift restriction on maximum memory allocated here.
+ *backing_store = nullptr;
+ return Handle<JSArrayBuffer>::null();
+ }
+ void* memory =
+ isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
+ if (!memory) {
+ *backing_store = nullptr;
+ return Handle<JSArrayBuffer>::null();
+ }
+
*backing_store = reinterpret_cast<byte*>(memory);
#if DEBUG
// Double check the API allocator actually zero-initialized the memory.
- for (int i = 0; i < size; i++) {
- DCHECK_EQ(0, (*backing_store)[i]);
+ byte* bytes = reinterpret_cast<byte*>(*backing_store);
+ for (size_t i = 0; i < size; i++) {
+ DCHECK_EQ(0, bytes[i]);
}
#endif
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
- JSArrayBuffer::Setup(buffer, isolate, false, memory, size);
+ JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
buffer->set_is_neuterable(false);
return buffer;
}
-} // namespace
+// Set the memory for a module instance to be the {memory} array buffer.
+void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
+ memory->set_is_neuterable(false);
+ instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
+ instance->mem_size = memory->byte_length()->Number();
+ instance->mem_buffer = memory;
+}
+
+// Allocate memory for a module instance as a new JSArrayBuffer.
+bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
+ WasmModuleInstance* instance) {
+ DCHECK(instance->module);
+ DCHECK(instance->mem_buffer.is_null());
+
+ if (instance->module->min_mem_size_log2 > WasmModule::kMaxMemSize) {
+ thrower->Error("Out of memory: wasm memory too large");
+ return false;
+ }
+ instance->mem_size = static_cast<size_t>(1)
+ << instance->module->min_mem_size_log2;
+ instance->mem_buffer =
+ NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
+ if (!instance->mem_start) {
+ thrower->Error("Out of memory: wasm memory");
+ instance->mem_size = 0;
+ return false;
+ }
+ return true;
+}
+
+bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
+ WasmModuleInstance* instance) {
+ instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
+
+ if (instance->globals_size > 0) {
+ instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
+ &instance->globals_start);
+ if (!instance->globals_start) {
+ // Not enough space for backing store of globals.
+ thrower->Error("Out of memory: wasm globals");
+ return false;
+ }
+ }
+ return true;
+}
+} // namespace
WasmModule::WasmModule()
- : globals(nullptr),
+ : shared_isolate(nullptr),
+ module_start(nullptr),
+ module_end(nullptr),
+ min_mem_size_log2(0),
+ max_mem_size_log2(0),
+ mem_export(false),
+ mem_external(false),
+ start_function_index(-1),
+ globals(nullptr),
signatures(nullptr),
functions(nullptr),
data_segments(nullptr),
- function_table(nullptr) {}
-
+ function_table(nullptr),
+ import_table(nullptr) {}
WasmModule::~WasmModule() {
if (globals) delete globals;
@@ -229,8 +291,33 @@ WasmModule::~WasmModule() {
if (functions) delete functions;
if (data_segments) delete data_segments;
if (function_table) delete function_table;
+ if (import_table) delete import_table;
}
+static MaybeHandle<JSFunction> LookupFunction(ErrorThrower& thrower,
+ Handle<JSObject> ffi,
+ uint32_t index,
+ Handle<String> name,
+ const char* cstr) {
+ if (!ffi.is_null()) {
+ MaybeHandle<Object> result = Object::GetProperty(ffi, name);
+ if (!result.is_null()) {
+ Handle<Object> obj = result.ToHandleChecked();
+ if (obj->IsJSFunction()) {
+ return Handle<JSFunction>::cast(obj);
+ } else {
+ thrower.Error("FFI function #%d:%s is not a JSFunction.", index, cstr);
+ return MaybeHandle<JSFunction>();
+ }
+ } else {
+ thrower.Error("FFI function #%d:%s not found.", index, cstr);
+ return MaybeHandle<JSFunction>();
+ }
+ } else {
+ thrower.Error("FFI table is not an object.");
+ return MaybeHandle<JSFunction>();
+ }
+}
// Instantiates a wasm module as a JSObject.
// * allocates a backing store of {mem_size} bytes.
@@ -242,95 +329,91 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Handle<JSArrayBuffer> memory) {
this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
-
Factory* factory = isolate->factory();
- // Memory is bigger than maximum supported size.
- if (memory.is_null() && min_mem_size_log2 > kMaxMemSize) {
- thrower.Error("Out of memory: wasm memory too large");
- return MaybeHandle<JSObject>();
- }
+ //-------------------------------------------------------------------------
+ // Allocate the instance and its JS counterpart.
+ //-------------------------------------------------------------------------
Handle<Map> map = factory->NewMap(
JS_OBJECT_TYPE,
JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
-
- //-------------------------------------------------------------------------
- // Allocate the module object.
- //-------------------------------------------------------------------------
- Handle<JSObject> module = factory->NewJSObjectFromMap(map, TENURED);
+ WasmModuleInstance instance(this);
+ std::vector<Handle<Code>> import_code;
+ instance.context = isolate->native_context();
+ instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
Handle<FixedArray> code_table =
factory->NewFixedArray(static_cast<int>(functions->size()), TENURED);
+ instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
//-------------------------------------------------------------------------
- // Allocate the linear memory.
+ // Allocate and initialize the linear memory.
//-------------------------------------------------------------------------
- uint32_t mem_size = 1 << min_mem_size_log2;
- byte* mem_addr = nullptr;
- Handle<JSArrayBuffer> mem_buffer;
- if (!memory.is_null()) {
- memory->set_is_neuterable(false);
- mem_addr = reinterpret_cast<byte*>(memory->backing_store());
- mem_size = memory->byte_length()->Number();
- mem_buffer = memory;
- } else {
- mem_buffer = NewArrayBuffer(isolate, mem_size, &mem_addr);
- if (!mem_addr) {
- // Not enough space for backing store of memory
- thrower.Error("Out of memory: wasm memory");
+ if (memory.is_null()) {
+ if (!AllocateMemory(&thrower, isolate, &instance)) {
return MaybeHandle<JSObject>();
}
+ } else {
+ SetMemory(&instance, memory);
}
-
- // Load initialized data segments.
- LoadDataSegments(this, mem_addr, mem_size);
-
- module->SetInternalField(kWasmMemArrayBuffer, *mem_buffer);
+ instance.js_object->SetInternalField(kWasmMemArrayBuffer,
+ *instance.mem_buffer);
+ LoadDataSegments(this, instance.mem_start, instance.mem_size);
if (mem_export) {
// Export the memory as a named property.
Handle<String> name = factory->InternalizeUtf8String("memory");
- JSObject::AddProperty(module, name, mem_buffer, READ_ONLY);
+ JSObject::AddProperty(instance.js_object, name, instance.mem_buffer,
+ READ_ONLY);
}
//-------------------------------------------------------------------------
// Allocate the globals area if necessary.
//-------------------------------------------------------------------------
- size_t globals_size = AllocateGlobalsOffsets(globals);
- byte* globals_addr = nullptr;
- if (globals_size > 0) {
- Handle<JSArrayBuffer> globals_buffer =
- NewArrayBuffer(isolate, mem_size, &globals_addr);
- if (!globals_addr) {
- // Not enough space for backing store of globals.
- thrower.Error("Out of memory: wasm globals");
- return MaybeHandle<JSObject>();
- }
-
- module->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
- } else {
- module->SetInternalField(kWasmGlobalsArrayBuffer, Smi::FromInt(0));
+ if (!AllocateGlobals(&thrower, isolate, &instance)) {
+ return MaybeHandle<JSObject>();
+ }
+ if (!instance.globals_buffer.is_null()) {
+ instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
+ *instance.globals_buffer);
}
//-------------------------------------------------------------------------
- // Compile all functions in the module.
+ // Compile wrappers to imported functions.
//-------------------------------------------------------------------------
- int index = 0;
+ uint32_t index = 0;
+ instance.function_table = BuildFunctionTable(isolate, this);
WasmLinker linker(isolate, functions->size());
ModuleEnv module_env;
module_env.module = this;
- module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr);
- module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr) + mem_size;
- module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr);
+ module_env.instance = &instance;
module_env.linker = &linker;
- module_env.function_code = nullptr;
- module_env.function_table = BuildFunctionTable(isolate, this);
- module_env.memory = memory;
- module_env.context = isolate->native_context();
module_env.asm_js = false;
+ if (import_table->size() > 0) {
+ instance.import_code = &import_code;
+ instance.import_code->reserve(import_table->size());
+ for (const WasmImport& import : *import_table) {
+ const char* cstr = GetName(import.function_name_offset);
+ Handle<String> name = factory->InternalizeUtf8String(cstr);
+ MaybeHandle<JSFunction> function =
+ LookupFunction(thrower, ffi, index, name, cstr);
+ if (function.is_null()) return MaybeHandle<JSObject>();
+ Handle<Code> code = compiler::CompileWasmToJSWrapper(
+ isolate, &module_env, function.ToHandleChecked(), import.sig, cstr);
+ instance.import_code->push_back(code);
+ index++;
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // Compile all functions in the module.
+ //-------------------------------------------------------------------------
+
// First pass: compile each function and initialize the code table.
+ index = 0;
for (const WasmFunction& func : *functions) {
if (thrower.error()) break;
+ DCHECK_EQ(index, func.func_index);
const char* cstr = GetName(func.name_offset);
Handle<String> name = factory->InternalizeUtf8String(cstr);
@@ -338,38 +421,21 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Handle<JSFunction> function = Handle<JSFunction>::null();
if (func.external) {
// Lookup external function in FFI object.
- if (!ffi.is_null()) {
- MaybeHandle<Object> result = Object::GetProperty(ffi, name);
- if (!result.is_null()) {
- Handle<Object> obj = result.ToHandleChecked();
- if (obj->IsJSFunction()) {
- function = Handle<JSFunction>::cast(obj);
- code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
- function, index);
- } else {
- thrower.Error("FFI function #%d:%s is not a JSFunction.", index,
- cstr);
- return MaybeHandle<JSObject>();
- }
- } else {
- thrower.Error("FFI function #%d:%s not found.", index, cstr);
- return MaybeHandle<JSObject>();
- }
- } else {
- thrower.Error("FFI table is not an object.");
- return MaybeHandle<JSObject>();
- }
+ MaybeHandle<JSFunction> function =
+ LookupFunction(thrower, ffi, index, name, cstr);
+ if (function.is_null()) return MaybeHandle<JSObject>();
+ code = compiler::CompileWasmToJSWrapper(
+ isolate, &module_env, function.ToHandleChecked(), func.sig, cstr);
} else {
// Compile the function.
- code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func,
- index);
+ code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (code.is_null()) {
thrower.Error("Compilation of #%d:%s failed.", index, cstr);
return MaybeHandle<JSObject>();
}
if (func.exported) {
- function = compiler::CompileJSToWasmWrapper(isolate, &module_env, name,
- code, module, index);
+ function = compiler::CompileJSToWasmWrapper(
+ isolate, &module_env, name, code, instance.js_object, index);
}
}
if (!code.is_null()) {
@@ -379,27 +445,54 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
}
if (func.exported) {
// Exported functions are installed as read-only properties on the module.
- JSObject::AddProperty(module, name, function, READ_ONLY);
+ JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
}
index++;
}
// Second pass: patch all direct call sites.
- linker.Link(module_env.function_table, this->function_table);
-
- module->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0));
- module->SetInternalField(kWasmModuleCodeTable, *code_table);
- return module;
+ linker.Link(instance.function_table, this->function_table);
+ instance.js_object->SetInternalField(kWasmModuleFunctionTable,
+ Smi::FromInt(0));
+
+ // Run the start function if one was specified.
+ if (this->start_function_index >= 0) {
+ HandleScope scope(isolate);
+ uint32_t index = static_cast<uint32_t>(this->start_function_index);
+ Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
+ Handle<Code> code = linker.GetFunctionCode(index);
+ Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
+ isolate, &module_env, name, code, instance.js_object, index);
+
+ // Call the JS function.
+ Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+ MaybeHandle<Object> retval =
+ Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
+
+ if (retval.is_null()) {
+ thrower.Error("WASM.instantiateModule(): start function failed");
+ }
+ }
+ return instance.js_object;
}
Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
DCHECK(IsValidFunction(index));
if (linker) return linker->GetFunctionCode(index);
- if (function_code) return function_code->at(index);
+ if (instance && instance->function_code) {
+ return instance->function_code->at(index);
+ }
return Handle<Code>::null();
}
+Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
+ DCHECK(IsValidImport(index));
+ if (instance && instance->import_code) {
+ return instance->import_code->at(index);
+ }
+ return Handle<Code>::null();
+}
compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
uint32_t index) {
@@ -436,43 +529,45 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
+ WasmModuleInstance instance(module);
- // Allocate temporary linear memory and globals.
- size_t mem_size = 1 << module->min_mem_size_log2;
- size_t globals_size = AllocateGlobalsOffsets(module->globals);
+ // Allocate and initialize the linear memory.
+ if (!AllocateMemory(&thrower, isolate, &instance)) {
+ return -1;
+ }
+ LoadDataSegments(module, instance.mem_start, instance.mem_size);
- base::SmartArrayPointer<byte> mem_addr(new byte[mem_size]);
- base::SmartArrayPointer<byte> globals_addr(new byte[globals_size]);
+ // Allocate the globals area if necessary.
+ if (!AllocateGlobals(&thrower, isolate, &instance)) {
+ return -1;
+ }
- memset(mem_addr.get(), 0, mem_size);
- memset(globals_addr.get(), 0, globals_size);
+ // Build the function table.
+ instance.function_table = BuildFunctionTable(isolate, module);
// Create module environment.
WasmLinker linker(isolate, module->functions->size());
ModuleEnv module_env;
module_env.module = module;
- module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr.get());
- module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr.get()) + mem_size;
- module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr.get());
+ module_env.instance = &instance;
module_env.linker = &linker;
- module_env.function_code = nullptr;
- module_env.function_table = BuildFunctionTable(isolate, module);
module_env.asm_js = false;
- // Load data segments.
- // TODO(titzer): throw instead of crashing if segments don't fit in memory?
- LoadDataSegments(module, mem_addr.get(), mem_size);
-
// Compile all functions.
Handle<Code> main_code = Handle<Code>::null(); // record last code.
- int index = 0;
+ uint32_t index = 0;
+ int main_index = 0;
for (const WasmFunction& func : *module->functions) {
+ DCHECK_EQ(index, func.func_index);
if (!func.external) {
// Compile the function and install it in the code table.
- Handle<Code> code = compiler::CompileWasmFunction(
- thrower, isolate, &module_env, func, index);
+ Handle<Code> code =
+ compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (!code.is_null()) {
- if (func.exported) main_code = code;
+ if (func.exported) {
+ main_code = code;
+ main_index = index;
+ }
linker.Finish(index, code);
}
if (thrower.error()) return -1;
@@ -480,30 +575,37 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
index++;
}
- if (!main_code.is_null()) {
- linker.Link(module_env.function_table, module->function_table);
-#if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
- // Run the main code on arm64 simulator.
- Simulator* simulator = Simulator::current(isolate);
- Simulator::CallArgument args[] = {Simulator::CallArgument(0),
- Simulator::CallArgument::End()};
- return static_cast<int32_t>(simulator->CallInt64(main_code->entry(), args));
-#elif USE_SIMULATOR
- // Run the main code on simulator.
- Simulator* simulator = Simulator::current(isolate);
- return static_cast<int32_t>(
- simulator->Call(main_code->entry(), 4, 0, 0, 0, 0));
-#else
- // Run the main code as raw machine code.
- int32_t (*raw_func)() = reinterpret_cast<int32_t (*)()>(
- reinterpret_cast<uintptr_t>(main_code->entry()));
- return raw_func();
-#endif
- } else {
- // No main code was found.
- isolate->Throw(*isolate->factory()->NewStringFromStaticChars(
- "WASM.compileRun() failed: no valid main code produced."));
+ if (main_code.is_null()) {
+ thrower.Error("WASM.compileRun() failed: no main code found");
+ return -1;
+ }
+
+ linker.Link(instance.function_table, instance.module->function_table);
+
+ // Wrap the main code so it can be called as a JS function.
+ Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
+ Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
+ Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
+ isolate, &module_env, name, main_code, module_object, main_index);
+
+ // Call the JS function.
+ Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+ MaybeHandle<Object> retval =
+ Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
+
+ // The result should be a number.
+ if (retval.is_null()) {
+ thrower.Error("WASM.compileRun() failed: Invocation was null");
+ return -1;
+ }
+ Handle<Object> result = retval.ToHandleChecked();
+ if (result->IsSmi()) {
+ return Smi::cast(*result)->value();
+ }
+ if (result->IsHeapNumber()) {
+ return static_cast<int32_t>(HeapNumber::cast(*result)->value());
}
+ thrower.Error("WASM.compileRun() failed: Return value should be number");
return -1;
}
} // namespace wasm
diff --git a/deps/v8/src/wasm/wasm-module.h b/deps/v8/src/wasm/wasm-module.h
index 5e2ba58a44..5f5777cebe 100644
--- a/deps/v8/src/wasm/wasm-module.h
+++ b/deps/v8/src/wasm/wasm-module.h
@@ -30,11 +30,13 @@ enum WasmSectionDeclCode {
kDeclGlobals = 0x03,
kDeclDataSegments = 0x04,
kDeclFunctionTable = 0x05,
- kDeclWLL = 0x11,
kDeclEnd = 0x06,
+ kDeclStartFunction = 0x07,
+ kDeclImportTable = 0x08,
+ kDeclWLL = 0x11,
};
-static const int kMaxModuleSectionCode = 6;
+static const int kMaxModuleSectionCode = 0x11;
enum WasmFunctionDeclBit {
kDeclFunctionName = 0x01,
@@ -48,22 +50,29 @@ static const size_t kDeclMemorySize = 3;
static const size_t kDeclGlobalSize = 6;
static const size_t kDeclDataSegmentSize = 13;
-// Static representation of a wasm function.
+// Static representation of a WASM function.
struct WasmFunction {
FunctionSig* sig; // signature of the function.
+ uint32_t func_index; // index into the function table.
uint16_t sig_index; // index into the signature table.
uint32_t name_offset; // offset in the module bytes of the name, if any.
uint32_t code_start_offset; // offset in the module bytes of code start.
uint32_t code_end_offset; // offset in the module bytes of code end.
- uint16_t local_int32_count; // number of int32 local variables.
- uint16_t local_int64_count; // number of int64 local variables.
- uint16_t local_float32_count; // number of float32 local variables.
- uint16_t local_float64_count; // number of float64 local variables.
+ uint16_t local_i32_count; // number of i32 local variables.
+ uint16_t local_i64_count; // number of i64 local variables.
+ uint16_t local_f32_count; // number of f32 local variables.
+ uint16_t local_f64_count; // number of f64 local variables.
bool exported; // true if this function is exported.
bool external; // true if this function is externally supplied.
};
-struct ModuleEnv; // forward declaration of decoder interface.
+// Static representation of an imported WASM function.
+struct WasmImport {
+ FunctionSig* sig; // signature of the function.
+ uint16_t sig_index; // index into the signature table.
+ uint32_t module_name_offset; // offset in module bytes of the module name.
+ uint32_t function_name_offset; // offset in module bytes of the import name.
+};
// Static representation of a wasm global variable.
struct WasmGlobal {
@@ -93,25 +102,27 @@ struct WasmModule {
uint8_t max_mem_size_log2; // maximum size of the memory (log base 2).
bool mem_export; // true if the memory is exported.
bool mem_external; // true if the memory is external.
+ int start_function_index; // start function, if any.
std::vector<WasmGlobal>* globals; // globals in this module.
std::vector<FunctionSig*>* signatures; // signatures in this module.
std::vector<WasmFunction>* functions; // functions in this module.
std::vector<WasmDataSegment>* data_segments; // data segments in this module.
std::vector<uint16_t>* function_table; // function table.
+ std::vector<WasmImport>* import_table; // import table.
WasmModule();
~WasmModule();
// Get a pointer to a string stored in the module bytes representing a name.
- const char* GetName(uint32_t offset) {
- CHECK(BoundsCheck(offset, offset + 1));
+ const char* GetName(uint32_t offset) const {
if (offset == 0) return "<?>"; // no name.
+ CHECK(BoundsCheck(offset, offset + 1));
return reinterpret_cast<const char*>(module_start + offset);
}
// Checks the given offset range is contained within the module bytes.
- bool BoundsCheck(uint32_t start, uint32_t end) {
+ bool BoundsCheck(uint32_t start, uint32_t end) const {
size_t size = module_end - module_start;
return start < size && end < size;
}
@@ -121,22 +132,42 @@ struct WasmModule {
Handle<JSArrayBuffer> memory);
};
+// An instantiated WASM module, including memory, function table, etc.
+struct WasmModuleInstance {
+ WasmModule* module; // static representation of the module.
+ // -- Heap allocated --------------------------------------------------------
+ Handle<JSObject> js_object; // JavaScript module object.
+ Handle<Context> context; // JavaScript native context.
+ Handle<JSArrayBuffer> mem_buffer; // Handle to array buffer of memory.
+ Handle<JSArrayBuffer> globals_buffer; // Handle to array buffer of globals.
+ Handle<FixedArray> function_table; // indirect function table.
+ std::vector<Handle<Code>>* function_code; // code objects for each function.
+ std::vector<Handle<Code>>* import_code; // code objects for each import.
+ // -- raw memory ------------------------------------------------------------
+ byte* mem_start; // start of linear memory.
+ size_t mem_size; // size of the linear memory.
+ // -- raw globals -----------------------------------------------------------
+ byte* globals_start; // start of the globals area.
+ size_t globals_size; // size of the globals area.
+
+ explicit WasmModuleInstance(WasmModule* m)
+ : module(m),
+ function_code(nullptr),
+ mem_start(nullptr),
+ mem_size(0),
+ globals_start(nullptr),
+ globals_size(0) {}
+};
+
// forward declaration.
class WasmLinker;
// Interface provided to the decoder/graph builder which contains only
// minimal information about the globals, functions, and function tables.
struct ModuleEnv {
- uintptr_t globals_area; // address of the globals area.
- uintptr_t mem_start; // address of the start of linear memory.
- uintptr_t mem_end; // address of the end of linear memory.
-
WasmModule* module;
+ WasmModuleInstance* instance;
WasmLinker* linker;
- std::vector<Handle<Code>>* function_code;
- Handle<FixedArray> function_table;
- Handle<JSArrayBuffer> memory;
- Handle<Context> context;
bool asm_js; // true if the module originated from asm.js.
bool IsValidGlobal(uint32_t index) {
@@ -148,6 +179,9 @@ struct ModuleEnv {
bool IsValidSignature(uint32_t index) {
return module && index < module->signatures->size();
}
+ bool IsValidImport(uint32_t index) {
+ return module && index < module->import_table->size();
+ }
MachineType GetGlobalType(uint32_t index) {
DCHECK(IsValidGlobal(index));
return module->globals->at(index).type;
@@ -156,23 +190,41 @@ struct ModuleEnv {
DCHECK(IsValidFunction(index));
return module->functions->at(index).sig;
}
+ FunctionSig* GetImportSignature(uint32_t index) {
+ DCHECK(IsValidImport(index));
+ return module->import_table->at(index).sig;
+ }
FunctionSig* GetSignature(uint32_t index) {
DCHECK(IsValidSignature(index));
return module->signatures->at(index);
}
size_t FunctionTableSize() {
- return module ? module->function_table->size() : 0;
+ return module && module->function_table ? module->function_table->size()
+ : 0;
}
Handle<Code> GetFunctionCode(uint32_t index);
+ Handle<Code> GetImportCode(uint32_t index);
Handle<FixedArray> GetFunctionTable();
- compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone, FunctionSig* sig);
+ static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone,
+ FunctionSig* sig);
+ static compiler::CallDescriptor* GetI32WasmCallDescriptor(
+ Zone* zone, compiler::CallDescriptor* descriptor);
compiler::CallDescriptor* GetCallDescriptor(Zone* zone, uint32_t index);
};
+// A helper for printing out the names of functions.
+struct WasmFunctionName {
+ const WasmFunction* function_;
+ const WasmModule* module_;
+ WasmFunctionName(const WasmFunction* function, const ModuleEnv* menv)
+ : function_(function), module_(menv ? menv->module : nullptr) {}
+};
+
std::ostream& operator<<(std::ostream& os, const WasmModule& module);
std::ostream& operator<<(std::ostream& os, const WasmFunction& function);
+std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
typedef Result<WasmModule*> ModuleResult;
typedef Result<WasmFunction*> FunctionResult;
@@ -185,6 +237,7 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
// For testing. Decode, verify, and run the last exported function in the
// given decoded module.
int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module);
+
} // namespace wasm
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/wasm/wasm-opcodes.cc b/deps/v8/src/wasm/wasm-opcodes.cc
index 25eef034d7..a609e03261 100644
--- a/deps/v8/src/wasm/wasm-opcodes.cc
+++ b/deps/v8/src/wasm/wasm-opcodes.cc
@@ -25,6 +25,20 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
}
+std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
+ if (sig.return_count() == 0) os << "v";
+ for (size_t i = 0; i < sig.return_count(); i++) {
+ os << WasmOpcodes::ShortNameOf(sig.GetReturn(i));
+ }
+ os << "_";
+ if (sig.parameter_count() == 0) os << "v";
+ for (size_t i = 0; i < sig.parameter_count(); i++) {
+ os << WasmOpcodes::ShortNameOf(sig.GetParam(i));
+ }
+ return os;
+}
+
+
#define DECLARE_SIG_ENUM(name, ...) kSigEnum_##name,
diff --git a/deps/v8/src/wasm/wasm-opcodes.h b/deps/v8/src/wasm/wasm-opcodes.h
index ae2843a6c1..7cb9c00449 100644
--- a/deps/v8/src/wasm/wasm-opcodes.h
+++ b/deps/v8/src/wasm/wasm-opcodes.h
@@ -66,6 +66,9 @@ struct MemoryAccess {
};
typedef Signature<LocalType> FunctionSig;
+std::ostream& operator<<(std::ostream& os, const FunctionSig& function);
+
+// TODO(titzer): Renumber all the opcodes to fill in holes.
// Control expressions and blocks.
#define FOREACH_CONTROL_OPCODE(V) \
@@ -80,7 +83,6 @@ typedef Signature<LocalType> FunctionSig;
V(TableSwitch, 0x08, _) \
V(Return, 0x14, _) \
V(Unreachable, 0x15, _)
-// TODO(titzer): numbering
// Constants, locals, globals, and calls.
#define FOREACH_MISC_OPCODE(V) \
@@ -94,7 +96,8 @@ typedef Signature<LocalType> FunctionSig;
V(LoadGlobal, 0x10, _) \
V(StoreGlobal, 0x11, _) \
V(CallFunction, 0x12, _) \
- V(CallIndirect, 0x13, _)
+ V(CallIndirect, 0x13, _) \
+ V(CallImport, 0x1F, _)
// Load memory expressions.
#define FOREACH_LOAD_MEM_OPCODE(V) \
@@ -398,7 +401,6 @@ class WasmOpcodes {
}
}
- // TODO(titzer): remove this method
static WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
if (type == MachineType::Int8()) {
return store ? kExprI32StoreMem8 : kExprI32LoadMem8S;