| Index: src/asmjs/asm-wasm-builder.cc
|
| diff --git a/src/asmjs/asm-wasm-builder.cc b/src/asmjs/asm-wasm-builder.cc
|
| index ac2585e6eaacc5453d317981309671a121c0ec22..d446c4e0a323aac07579442837fa5e4b5fc35274 100644
|
| --- a/src/asmjs/asm-wasm-builder.cc
|
| +++ b/src/asmjs/asm-wasm-builder.cc
|
| @@ -32,6 +32,7 @@ namespace wasm {
|
| } while (false)
|
|
|
| enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
|
| +enum ValueFate { kDrop, kLeaveOnStack };
|
|
|
| struct ForeignVariable {
|
| Handle<Name> name;
|
| @@ -61,8 +62,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| typer_(typer),
|
| breakable_blocks_(zone),
|
| foreign_variables_(zone),
|
| - init_function_index_(0),
|
| - foreign_init_function_index_(0),
|
| + init_function_(nullptr),
|
| + foreign_init_function_(nullptr),
|
| next_table_index_(0),
|
| function_tables_(base::HashMap::PointersMatch,
|
| ZoneHashMap::kDefaultHashMapCapacity,
|
| @@ -72,35 +73,33 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| }
|
|
|
| void InitializeInitFunction() {
|
| - init_function_index_ = builder_->AddFunction();
|
| FunctionSig::Builder b(zone(), 0, 0);
|
| - current_function_builder_ = builder_->FunctionAt(init_function_index_);
|
| - current_function_builder_->SetSignature(b.Build());
|
| - builder_->MarkStartFunction(init_function_index_);
|
| - current_function_builder_ = nullptr;
|
| + init_function_ = builder_->AddFunction(b.Build());
|
| + builder_->MarkStartFunction(init_function_);
|
| }
|
|
|
| void BuildForeignInitFunction() {
|
| - foreign_init_function_index_ = builder_->AddFunction();
|
| + foreign_init_function_ = builder_->AddFunction();
|
| FunctionSig::Builder b(zone(), 0, foreign_variables_.size());
|
| for (auto i = foreign_variables_.begin(); i != foreign_variables_.end();
|
| ++i) {
|
| b.AddParam(i->type);
|
| }
|
| - current_function_builder_ =
|
| - builder_->FunctionAt(foreign_init_function_index_);
|
| - current_function_builder_->SetExported();
|
| - current_function_builder_->SetName(
|
| + foreign_init_function_->SetExported();
|
| + std::string raw_name = "__foreign_init__";
|
| + foreign_init_function_->SetName(
|
| AsmWasmBuilder::foreign_init_name,
|
| static_cast<int>(strlen(AsmWasmBuilder::foreign_init_name)));
|
| - current_function_builder_->SetSignature(b.Build());
|
| +
|
| + foreign_init_function_->SetName(raw_name.data(),
|
| + static_cast<int>(raw_name.size()));
|
| + foreign_init_function_->SetSignature(b.Build());
|
| for (size_t pos = 0; pos < foreign_variables_.size(); ++pos) {
|
| - current_function_builder_->EmitGetLocal(static_cast<uint32_t>(pos));
|
| + foreign_init_function_->EmitGetLocal(static_cast<uint32_t>(pos));
|
| ForeignVariable* fv = &foreign_variables_[pos];
|
| uint32_t index = LookupOrInsertGlobal(fv->var, fv->type);
|
| - current_function_builder_->EmitWithVarInt(kExprSetGlobal, index);
|
| + foreign_init_function_->EmitWithVarInt(kExprSetGlobal, index);
|
| }
|
| - current_function_builder_ = nullptr;
|
| }
|
|
|
| i::Handle<i::FixedArray> GetForeignArgs() {
|
| @@ -113,7 +112,20 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| return ret;
|
| }
|
|
|
| + void BuildImports() {
|
| + for (const AsmTyper::FFIUseSignature& ffi : typer_->FFIUseSignatures()) {
|
| + size_t ret_count = ffi.return_type_ == AsmType::Void() ? 0 : 1;
|
| + FunctionSig::Builder b(zone_, ret_count, ffi.arg_types_.size());
|
| + for (AsmType* arg : ffi.arg_types_) b.AddParam(TypeFrom(arg));
|
| + if (ffi.return_type_ != AsmType::Void()) {
|
| + b.AddReturn(TypeFrom(ffi.return_type_));
|
| + }
|
| + imported_function_table_.AddFunction(ffi.var, b.Build());
|
| + }
|
| + }
|
| +
|
| void Build() {
|
| + BuildImports();
|
| InitializeInitFunction();
|
| RECURSE(VisitFunctionLiteral(literal_));
|
| BuildForeignInitFunction();
|
| @@ -124,8 +136,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| void VisitFunctionDeclaration(FunctionDeclaration* decl) {
|
| DCHECK_EQ(kModuleScope, scope_);
|
| DCHECK_NULL(current_function_builder_);
|
| - uint32_t index = LookupOrInsertFunction(decl->proxy()->var());
|
| - current_function_builder_ = builder_->FunctionAt(index);
|
| + current_function_builder_ = LookupOrInsertFunction(decl->proxy()->var());
|
| scope_ = kFuncScope;
|
| RECURSE(Visit(decl->fun()));
|
| scope_ = kModuleScope;
|
| @@ -157,8 +168,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| }
|
| }
|
| if (scope_ == kFuncScope) {
|
| - BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
|
| - false);
|
| + BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock);
|
| RECURSE(VisitStatements(stmt->statements()));
|
| } else {
|
| RECURSE(VisitStatements(stmt->statements()));
|
| @@ -171,10 +181,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
|
|
| public:
|
| BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
|
| - WasmOpcode opcode, bool is_loop)
|
| + WasmOpcode opcode)
|
| : builder_(builder) {
|
| - builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
|
| - builder_->current_function_builder_->Emit(opcode);
|
| + builder_->breakable_blocks_.push_back(
|
| + std::make_pair(stmt, opcode == kExprLoop));
|
| + // block and loops have a type immediate.
|
| + builder_->current_function_builder_->EmitWithU8(opcode, kLocalVoid);
|
| }
|
| ~BlockVisitor() {
|
| builder_->current_function_builder_->Emit(kExprEnd);
|
| @@ -183,7 +195,32 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| };
|
|
|
| void VisitExpressionStatement(ExpressionStatement* stmt) {
|
| - RECURSE(Visit(stmt->expression()));
|
| + VisitForEffect(stmt->expression());
|
| + }
|
| +
|
| + void VisitForEffect(Expression* expr) {
|
| + if (expr->IsAssignment()) {
|
| + // Don't emit drops for assignments. Instead use SetLocal/GetLocal.
|
| + VisitAssignment(expr->AsAssignment(), kDrop);
|
| + return;
|
| + }
|
| + if (expr->IsCall()) {
|
| + // Only emit a drop if the call has a non-void return value.
|
| + if (VisitCallExpression(expr->AsCall()) && scope_ == kFuncScope) {
|
| + current_function_builder_->Emit(kExprDrop);
|
| + }
|
| + return;
|
| + }
|
| + if (expr->IsBinaryOperation()) {
|
| + BinaryOperation* binop = expr->AsBinaryOperation();
|
| + if (binop->op() == Token::COMMA) {
|
| + VisitForEffect(binop->left());
|
| + VisitForEffect(binop->right());
|
| + return;
|
| + }
|
| + }
|
| + RECURSE(Visit(expr));
|
| + if (scope_ == kFuncScope) current_function_builder_->Emit(kExprDrop);
|
| }
|
|
|
| void VisitEmptyStatement(EmptyStatement* stmt) {}
|
| @@ -193,7 +230,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| void VisitIfStatement(IfStatement* stmt) {
|
| DCHECK_EQ(kFuncScope, scope_);
|
| RECURSE(Visit(stmt->condition()));
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| // WASM ifs come with implement blocks for both arms.
|
| breakable_blocks_.push_back(std::make_pair(nullptr, false));
|
| if (stmt->HasThenStatement()) {
|
| @@ -207,48 +244,26 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| breakable_blocks_.pop_back();
|
| }
|
|
|
| - void VisitContinueStatement(ContinueStatement* stmt) {
|
| + void DoBreakOrContinue(BreakableStatement* target, bool is_continue) {
|
| DCHECK_EQ(kFuncScope, scope_);
|
| - DCHECK_NOT_NULL(stmt->target());
|
| - int i = static_cast<int>(breakable_blocks_.size()) - 1;
|
| - int block_distance = 0;
|
| - for (; i >= 0; i--) {
|
| + for (int i = static_cast<int>(breakable_blocks_.size()) - 1; i >= 0; --i) {
|
| auto elem = breakable_blocks_.at(i);
|
| - if (elem.first == stmt->target()) {
|
| - DCHECK(elem.second);
|
| - break;
|
| - } else if (elem.second) {
|
| - block_distance += 2;
|
| - } else {
|
| - block_distance += 1;
|
| + if (elem.first == target && elem.second == is_continue) {
|
| + int block_distance = static_cast<int>(breakable_blocks_.size() - i - 1);
|
| + current_function_builder_->Emit(kExprBr);
|
| + current_function_builder_->EmitVarInt(block_distance);
|
| + return;
|
| }
|
| }
|
| - DCHECK(i >= 0);
|
| - current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
|
| - current_function_builder_->EmitVarInt(block_distance);
|
| + UNREACHABLE(); // statement not found
|
| + }
|
| +
|
| + void VisitContinueStatement(ContinueStatement* stmt) {
|
| + DoBreakOrContinue(stmt->target(), true);
|
| }
|
|
|
| void VisitBreakStatement(BreakStatement* stmt) {
|
| - DCHECK_EQ(kFuncScope, scope_);
|
| - DCHECK_NOT_NULL(stmt->target());
|
| - int i = static_cast<int>(breakable_blocks_.size()) - 1;
|
| - int block_distance = 0;
|
| - for (; i >= 0; i--) {
|
| - auto elem = breakable_blocks_.at(i);
|
| - if (elem.first == stmt->target()) {
|
| - if (elem.second) {
|
| - block_distance++;
|
| - }
|
| - break;
|
| - } else if (elem.second) {
|
| - block_distance += 2;
|
| - } else {
|
| - block_distance += 1;
|
| - }
|
| - }
|
| - DCHECK(i >= 0);
|
| - current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
|
| - current_function_builder_->EmitVarInt(block_distance);
|
| + DoBreakOrContinue(stmt->target(), false);
|
| }
|
|
|
| void VisitReturnStatement(ReturnStatement* stmt) {
|
| @@ -258,9 +273,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| scope_ = kModuleScope;
|
| } else if (scope_ == kFuncScope) {
|
| RECURSE(Visit(stmt->expression()));
|
| - uint8_t arity =
|
| - TypeOf(stmt->expression()) == kAstStmt ? ARITY_0 : ARITY_1;
|
| - current_function_builder_->EmitWithU8(kExprReturn, arity);
|
| + current_function_builder_->Emit(kExprReturn);
|
| } else {
|
| UNREACHABLE();
|
| }
|
| @@ -276,7 +289,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| VisitVariableProxy(tag);
|
| current_function_builder_->EmitI32Const(node->begin);
|
| current_function_builder_->Emit(kExprI32LtS);
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| if_depth++;
|
| breakable_blocks_.push_back(std::make_pair(nullptr, false));
|
| HandleCase(node->left, case_to_block, tag, default_block, if_depth);
|
| @@ -286,7 +299,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| VisitVariableProxy(tag);
|
| current_function_builder_->EmitI32Const(node->end);
|
| current_function_builder_->Emit(kExprI32GtS);
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| if_depth++;
|
| breakable_blocks_.push_back(std::make_pair(nullptr, false));
|
| HandleCase(node->right, case_to_block, tag, default_block, if_depth);
|
| @@ -296,9 +309,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| VisitVariableProxy(tag);
|
| current_function_builder_->EmitI32Const(node->begin);
|
| current_function_builder_->Emit(kExprI32Eq);
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| DCHECK(case_to_block.find(node->begin) != case_to_block.end());
|
| - current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
|
| + current_function_builder_->Emit(kExprBr);
|
| current_function_builder_->EmitVarInt(1 + if_depth +
|
| case_to_block[node->begin]);
|
| current_function_builder_->Emit(kExprEnd);
|
| @@ -310,22 +323,22 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| } else {
|
| VisitVariableProxy(tag);
|
| }
|
| - current_function_builder_->EmitWithU8(kExprBrTable, ARITY_0);
|
| + current_function_builder_->Emit(kExprBrTable);
|
| current_function_builder_->EmitVarInt(node->end - node->begin + 1);
|
| - for (int v = node->begin; v <= node->end; v++) {
|
| + for (int v = node->begin; v <= node->end; ++v) {
|
| if (case_to_block.find(v) != case_to_block.end()) {
|
| - byte break_code[] = {BR_TARGET(if_depth + case_to_block[v])};
|
| - current_function_builder_->EmitCode(break_code, sizeof(break_code));
|
| + uint32_t target = if_depth + case_to_block[v];
|
| + current_function_builder_->EmitVarInt(target);
|
| } else {
|
| - byte break_code[] = {BR_TARGET(if_depth + default_block)};
|
| - current_function_builder_->EmitCode(break_code, sizeof(break_code));
|
| + uint32_t target = if_depth + default_block;
|
| + current_function_builder_->EmitVarInt(target);
|
| }
|
| if (v == kMaxInt) {
|
| break;
|
| }
|
| }
|
| - byte break_code[] = {BR_TARGET(if_depth + default_block)};
|
| - current_function_builder_->EmitCode(break_code, sizeof(break_code));
|
| + uint32_t target = if_depth + default_block;
|
| + current_function_builder_->EmitVarInt(target);
|
| }
|
|
|
| while (if_depth-- != prev_if_depth) {
|
| @@ -342,14 +355,14 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| if (case_count == 0) {
|
| return;
|
| }
|
| - BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false);
|
| + BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock);
|
| ZoneVector<BlockVisitor*> blocks(zone_);
|
| ZoneVector<int32_t> cases(zone_);
|
| ZoneMap<int, unsigned int> case_to_block(zone_);
|
| bool has_default = false;
|
| - for (int i = case_count - 1; i >= 0; i--) {
|
| + for (int i = case_count - 1; i >= 0; --i) {
|
| CaseClause* clause = clauses->at(i);
|
| - blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false));
|
| + blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock));
|
| if (!clause->is_default()) {
|
| Literal* label = clause->label()->AsLiteral();
|
| Handle<Object> value = label->value();
|
| @@ -366,12 +379,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| }
|
| if (!has_default || case_count > 1) {
|
| int default_block = has_default ? case_count - 1 : case_count;
|
| - BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false);
|
| + BlockVisitor switch_logic_block(this, nullptr, kExprBlock);
|
| CaseNode* root = OrderCases(&cases, zone_);
|
| HandleCase(root, case_to_block, tag, default_block, 0);
|
| if (root->left != nullptr || root->right != nullptr ||
|
| root->begin == root->end) {
|
| - current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
|
| + current_function_builder_->Emit(kExprBr);
|
| current_function_builder_->EmitVarInt(default_block);
|
| }
|
| }
|
| @@ -388,22 +401,24 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
|
|
| void VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| DCHECK_EQ(kFuncScope, scope_);
|
| - BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
|
| + BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock);
|
| + BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
|
| RECURSE(Visit(stmt->body()));
|
| RECURSE(Visit(stmt->cond()));
|
| - current_function_builder_->Emit(kExprIf);
|
| - current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| + current_function_builder_->EmitWithU8(kExprBr, 1);
|
| current_function_builder_->Emit(kExprEnd);
|
| }
|
|
|
| void VisitWhileStatement(WhileStatement* stmt) {
|
| DCHECK_EQ(kFuncScope, scope_);
|
| - BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
|
| + BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock);
|
| + BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
|
| RECURSE(Visit(stmt->cond()));
|
| breakable_blocks_.push_back(std::make_pair(nullptr, false));
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| RECURSE(Visit(stmt->body()));
|
| - current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
|
| + current_function_builder_->EmitWithU8(kExprBr, 1);
|
| current_function_builder_->Emit(kExprEnd);
|
| breakable_blocks_.pop_back();
|
| }
|
| @@ -413,13 +428,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| if (stmt->init() != nullptr) {
|
| RECURSE(Visit(stmt->init()));
|
| }
|
| - BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
|
| + BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock);
|
| + BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
|
| if (stmt->cond() != nullptr) {
|
| RECURSE(Visit(stmt->cond()));
|
| current_function_builder_->Emit(kExprI32Eqz);
|
| - current_function_builder_->Emit(kExprIf);
|
| - current_function_builder_->Emit(kExprNop);
|
| - current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 2);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
|
| + current_function_builder_->EmitWithU8(kExprBr, 2);
|
| current_function_builder_->Emit(kExprEnd);
|
| }
|
| if (stmt->body() != nullptr) {
|
| @@ -428,8 +443,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| if (stmt->next() != nullptr) {
|
| RECURSE(Visit(stmt->next()));
|
| }
|
| - current_function_builder_->Emit(kExprNop);
|
| - current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
|
| + current_function_builder_->EmitWithU8(kExprBr, 0);
|
| }
|
|
|
| void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
|
| @@ -446,19 +460,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| DeclarationScope* scope = expr->scope();
|
| if (scope_ == kFuncScope) {
|
| if (auto* func_type = typer_->TypeOf(expr)->AsFunctionType()) {
|
| - // Build the signature for the function.
|
| - LocalType return_type = TypeFrom(func_type->ReturnType());
|
| + // Add the parameters for the function.
|
| const auto& arguments = func_type->Arguments();
|
| - FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
|
| - arguments.size());
|
| - if (return_type != kAstStmt) b.AddReturn(return_type);
|
| for (int i = 0; i < expr->parameter_count(); ++i) {
|
| LocalType type = TypeFrom(arguments[i]);
|
| DCHECK_NE(kAstStmt, type);
|
| - b.AddParam(type);
|
| InsertParameter(scope->parameter(i), type, i);
|
| }
|
| - current_function_builder_->SetSignature(b.Build());
|
| } else {
|
| UNREACHABLE();
|
| }
|
| @@ -476,7 +484,24 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| RECURSE(Visit(expr->condition()));
|
| // WASM ifs come with implicit blocks for both arms.
|
| breakable_blocks_.push_back(std::make_pair(nullptr, false));
|
| - current_function_builder_->Emit(kExprIf);
|
| + LocalTypeCode type;
|
| + switch (TypeOf(expr)) {
|
| + case kAstI32:
|
| + type = kLocalI32;
|
| + break;
|
| + case kAstI64:
|
| + type = kLocalI64;
|
| + break;
|
| + case kAstF32:
|
| + type = kLocalF32;
|
| + break;
|
| + case kAstF64:
|
| + type = kLocalF64;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + current_function_builder_->EmitWithU8(kExprIf, type);
|
| RECURSE(Visit(expr->then_expression()));
|
| current_function_builder_->Emit(kExprElse);
|
| RECURSE(Visit(expr->else_expression()));
|
| @@ -554,9 +579,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| } else if (scope_ == kExportScope) {
|
| Variable* var = expr->var();
|
| DCHECK(var->is_function());
|
| - uint32_t index = LookupOrInsertFunction(var);
|
| - builder_->FunctionAt(index)->SetExported();
|
| - builder_->FunctionAt(index)->SetName(
|
| + WasmFunctionBuilder* function = LookupOrInsertFunction(var);
|
| + function->SetExported();
|
| + function->SetName(
|
| AsmWasmBuilder::single_function_name,
|
| static_cast<int>(strlen(AsmWasmBuilder::single_function_name)));
|
| }
|
| @@ -609,11 +634,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| DCHECK(name->IsPropertyName());
|
| const AstRawString* raw_name = name->AsRawPropertyName();
|
| if (var->is_function()) {
|
| - uint32_t index = LookupOrInsertFunction(var);
|
| - builder_->FunctionAt(index)->SetExported();
|
| - builder_->FunctionAt(index)->SetName(
|
| - reinterpret_cast<const char*>(raw_name->raw_data()),
|
| - raw_name->length());
|
| + WasmFunctionBuilder* function = LookupOrInsertFunction(var);
|
| + function->SetExported();
|
| + function->SetName(reinterpret_cast<const char*>(raw_name->raw_data()),
|
| + raw_name->length());
|
| }
|
| }
|
| }
|
| @@ -621,7 +645,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
|
|
|
| void LoadInitFunction() {
|
| - current_function_builder_ = builder_->FunctionAt(init_function_index_);
|
| + current_function_builder_ = init_function_;
|
| scope_ = kInitScope;
|
| }
|
|
|
| @@ -650,7 +674,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| 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()));
|
| + builder_->AddIndirectFunction(
|
| + LookupOrInsertFunction(func->var())->func_index());
|
| }
|
| }
|
|
|
| @@ -680,12 +705,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| private:
|
| class ImportedFunctionIndices : public ZoneObject {
|
| public:
|
| - const char* name_;
|
| - int name_length_;
|
| + bool has_name_;
|
| WasmModuleBuilder::SignatureMap signature_to_index_;
|
|
|
| - ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
|
| - : name_(name), name_length_(name_length), signature_to_index_(zone) {}
|
| + explicit ImportedFunctionIndices(Zone* zone)
|
| + : has_name_(false), signature_to_index_(zone) {}
|
| };
|
| ZoneHashMap table_;
|
| AsmWasmBuilderImpl* builder_;
|
| @@ -697,30 +721,51 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| ZoneAllocationPolicy(builder->zone())),
|
| builder_(builder) {}
|
|
|
| - void AddImport(Variable* v, const 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;
|
| + // Set the imported name of a variable. Must happen after all signatures
|
| + // (and thus import indices) are added for a given variable.
|
| + void SetImportName(Variable* v, const char* name, int name_length) {
|
| + auto indices = GetEntry(v);
|
| + if (indices) {
|
| + for (auto entry : indices->signature_to_index_) {
|
| + uint32_t index = entry.second;
|
| + builder_->builder_->SetImportName(index, name, name_length);
|
| + }
|
| + indices->has_name_ = true;
|
| + }
|
| }
|
|
|
| + // Get a function's index. Does not insert new entries.
|
| uint32_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 {
|
| - uint32_t index = builder_->builder_->AddImport(
|
| - indices->name_, indices->name_length_, sig);
|
| + auto indices = GetEntry(v);
|
| + DCHECK_NOT_NULL(indices);
|
| + auto pos = indices->signature_to_index_.find(sig);
|
| + DCHECK(pos != indices->signature_to_index_.end());
|
| + return pos->second;
|
| + }
|
| +
|
| + // Add a function and register it as an import with the builder.
|
| + void AddFunction(Variable* v, FunctionSig* sig) {
|
| + auto entry = table_.LookupOrInsert(
|
| + v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
|
| + if (entry->value == nullptr) {
|
| + entry->value =
|
| + new (builder_->zone()) ImportedFunctionIndices(builder_->zone());
|
| + }
|
| + auto indices = reinterpret_cast<ImportedFunctionIndices*>(entry->value);
|
| + DCHECK(!indices->has_name_);
|
| + auto pos = indices->signature_to_index_.find(sig);
|
| + if (pos == indices->signature_to_index_.end()) {
|
| + // A new import. Name is not known up front.
|
| + uint32_t index = builder_->builder_->AddImport(nullptr, 0, sig);
|
| indices->signature_to_index_[sig] = index;
|
| - return index;
|
| }
|
| }
|
| +
|
| + ImportedFunctionIndices* GetEntry(Variable* v) {
|
| + auto entry = table_.Lookup(v, ComputePointerHash(v));
|
| + if (entry == nullptr) return nullptr;
|
| + return reinterpret_cast<ImportedFunctionIndices*>(entry->value);
|
| + }
|
| };
|
|
|
| void EmitAssignmentLhs(Expression* target, MachineType* mtype) {
|
| @@ -782,7 +827,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| RECURSE(Visit(value));
|
| }
|
|
|
| - void EmitAssignment(Assignment* expr, MachineType type) {
|
| + void EmitAssignment(Assignment* expr, MachineType type, ValueFate fate) {
|
| // Match the left hand side of the assignment.
|
| VariableProxy* target_var = expr->target()->AsVariableProxy();
|
| if (target_var != nullptr) {
|
| @@ -791,11 +836,19 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| LocalType var_type = TypeOf(expr);
|
| DCHECK_NE(kAstStmt, var_type);
|
| if (var->IsContextSlot()) {
|
| - current_function_builder_->EmitWithVarInt(
|
| - kExprSetGlobal, LookupOrInsertGlobal(var, var_type));
|
| + uint32_t index = LookupOrInsertGlobal(var, var_type);
|
| + current_function_builder_->EmitWithVarInt(kExprSetGlobal, index);
|
| + if (fate == kLeaveOnStack) {
|
| + current_function_builder_->EmitWithVarInt(kExprGetGlobal, index);
|
| + }
|
| } else {
|
| - current_function_builder_->EmitSetLocal(
|
| - LookupOrInsertLocal(var, var_type));
|
| + if (fate == kDrop) {
|
| + current_function_builder_->EmitSetLocal(
|
| + LookupOrInsertLocal(var, var_type));
|
| + } else {
|
| + current_function_builder_->EmitTeeLocal(
|
| + LookupOrInsertLocal(var, var_type));
|
| + }
|
| }
|
| }
|
|
|
| @@ -807,6 +860,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| ->IsA(AsmType::Float32Array())) {
|
| current_function_builder_->Emit(kExprF32ConvertF64);
|
| }
|
| + // Note that unlike StoreMem, AsmjsStoreMem ignores out-of-bounds writes.
|
| WasmOpcode opcode;
|
| if (type == MachineType::Int8()) {
|
| opcode = kExprI32AsmjsStoreMem8;
|
| @@ -828,6 +882,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| UNREACHABLE();
|
| }
|
| current_function_builder_->Emit(opcode);
|
| + if (fate == kDrop) {
|
| + // Asm.js stores to memory leave their result on the stack.
|
| + current_function_builder_->Emit(kExprDrop);
|
| + }
|
| }
|
|
|
| if (target_var == nullptr && target_prop == nullptr) {
|
| @@ -836,6 +894,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| }
|
|
|
| void VisitAssignment(Assignment* expr) {
|
| + VisitAssignment(expr, kLeaveOnStack);
|
| + }
|
| +
|
| + void VisitAssignment(Assignment* expr, ValueFate fate) {
|
| bool as_init = false;
|
| if (scope_ == kModuleScope) {
|
| // Skip extra assignment inserted by the parser when in this form:
|
| @@ -853,7 +915,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| if (typer_->TypeOf(target)->AsFFIType() != nullptr) {
|
| const AstRawString* name =
|
| prop->key()->AsLiteral()->AsRawPropertyName();
|
| - imported_function_table_.AddImport(
|
| + imported_function_table_.SetImportName(
|
| target->var(), reinterpret_cast<const char*>(name->raw_data()),
|
| name->length());
|
| }
|
| @@ -881,12 +943,12 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| }
|
|
|
| if (as_init) LoadInitFunction();
|
| - MachineType mtype;
|
| + MachineType mtype = MachineType::None();
|
| bool is_nop = false;
|
| EmitAssignmentLhs(expr->target(), &mtype);
|
| EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
|
| if (!is_nop) {
|
| - EmitAssignment(expr, mtype);
|
| + EmitAssignment(expr, mtype, fate);
|
| }
|
| if (as_init) UnLoadInitFunction();
|
| }
|
| @@ -1111,11 +1173,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
|
|
| // if set_local(tmp, x) < 0
|
| Visit(call->arguments()->at(0));
|
| - current_function_builder_->EmitSetLocal(tmp.index());
|
| + current_function_builder_->EmitTeeLocal(tmp.index());
|
| byte code[] = {WASM_I8(0)};
|
| current_function_builder_->EmitCode(code, sizeof(code));
|
| current_function_builder_->Emit(kExprI32LtS);
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
|
|
|
| // then (0 - tmp)
|
| current_function_builder_->EmitCode(code, sizeof(code));
|
| @@ -1147,13 +1209,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
|
|
| // if set_local(tmp_x, x) < set_local(tmp_y, y)
|
| Visit(call->arguments()->at(0));
|
| - current_function_builder_->EmitSetLocal(tmp_x.index());
|
| + current_function_builder_->EmitTeeLocal(tmp_x.index());
|
|
|
| Visit(call->arguments()->at(1));
|
| - current_function_builder_->EmitSetLocal(tmp_y.index());
|
| + current_function_builder_->EmitTeeLocal(tmp_y.index());
|
|
|
| current_function_builder_->Emit(kExprI32LeS);
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
|
|
|
| // then tmp_x
|
| current_function_builder_->EmitGetLocal(tmp_x.index());
|
| @@ -1183,13 +1245,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| // if set_local(tmp_x, x) < set_local(tmp_y, y)
|
| Visit(call->arguments()->at(0));
|
|
|
| - current_function_builder_->EmitSetLocal(tmp_x.index());
|
| + current_function_builder_->EmitTeeLocal(tmp_x.index());
|
|
|
| Visit(call->arguments()->at(1));
|
| - current_function_builder_->EmitSetLocal(tmp_y.index());
|
| + current_function_builder_->EmitTeeLocal(tmp_y.index());
|
|
|
| current_function_builder_->Emit(kExprI32LeS);
|
| - current_function_builder_->Emit(kExprIf);
|
| + current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
|
|
|
| // then tmp_y
|
| current_function_builder_->EmitGetLocal(tmp_y.index());
|
| @@ -1275,18 +1337,20 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| }
|
| }
|
|
|
| - void VisitCall(Call* expr) {
|
| + void VisitCall(Call* expr) { VisitCallExpression(expr); }
|
| +
|
| + bool VisitCallExpression(Call* expr) {
|
| Call::CallType call_type = expr->GetCallType();
|
| + bool returns_value = true;
|
| switch (call_type) {
|
| case Call::OTHER_CALL: {
|
| DCHECK_EQ(kFuncScope, scope_);
|
| VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
| if (proxy != nullptr) {
|
| if (VisitStdlibFunction(expr, proxy)) {
|
| - return;
|
| + return true;
|
| }
|
| }
|
| - uint32_t index;
|
| VariableProxy* vp = expr->expression()->AsVariableProxy();
|
| DCHECK_NOT_NULL(vp);
|
| if (typer_->TypeOf(vp)->AsFFIType() != nullptr) {
|
| @@ -1296,22 +1360,23 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| args->length());
|
| if (return_type != kAstStmt) {
|
| sig.AddReturn(return_type);
|
| + } else {
|
| + returns_value = false;
|
| }
|
| for (int i = 0; i < args->length(); ++i) {
|
| sig.AddParam(TypeOf(args->at(i)));
|
| }
|
| - index =
|
| + uint32_t index =
|
| imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
|
| VisitCallArgs(expr);
|
| - current_function_builder_->Emit(kExprCallImport);
|
| - current_function_builder_->EmitVarInt(expr->arguments()->length());
|
| + current_function_builder_->Emit(kExprCallFunction);
|
| current_function_builder_->EmitVarInt(index);
|
| } else {
|
| - index = LookupOrInsertFunction(vp->var());
|
| + WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var());
|
| VisitCallArgs(expr);
|
| current_function_builder_->Emit(kExprCallFunction);
|
| - current_function_builder_->EmitVarInt(expr->arguments()->length());
|
| - current_function_builder_->EmitVarInt(index);
|
| + current_function_builder_->EmitVarInt(function->func_index());
|
| + returns_value = function->signature()->return_count() > 0;
|
| }
|
| break;
|
| }
|
| @@ -1322,18 +1387,28 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| VariableProxy* var = p->obj()->AsVariableProxy();
|
| DCHECK_NOT_NULL(var);
|
| FunctionTableIndices* indices = LookupFunctionTable(var->var());
|
| - RECURSE(Visit(p->key()));
|
| + Visit(p->key()); // TODO(titzer): should use RECURSE()
|
| +
|
| + // We have to use a temporary for the correct order of evaluation.
|
| current_function_builder_->EmitI32Const(indices->start_index);
|
| current_function_builder_->Emit(kExprI32Add);
|
| + WasmTemporary tmp(current_function_builder_, kAstI32);
|
| + current_function_builder_->EmitSetLocal(tmp.index());
|
| +
|
| VisitCallArgs(expr);
|
| +
|
| + current_function_builder_->EmitGetLocal(tmp.index());
|
| current_function_builder_->Emit(kExprCallIndirect);
|
| - current_function_builder_->EmitVarInt(expr->arguments()->length());
|
| current_function_builder_->EmitVarInt(indices->signature_index);
|
| + returns_value =
|
| + builder_->GetSignature(indices->signature_index)->return_count() >
|
| + 0;
|
| break;
|
| }
|
| default:
|
| UNREACHABLE();
|
| }
|
| + return returns_value;
|
| }
|
|
|
| void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
|
| @@ -1519,16 +1594,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| RECURSE(Visit(GetLeft(expr)));
|
| } else {
|
| if (expr->op() == Token::COMMA) {
|
| - current_function_builder_->Emit(kExprBlock);
|
| + RECURSE(VisitForEffect(expr->left()));
|
| + RECURSE(Visit(expr->right()));
|
| + return;
|
| }
|
| -
|
| RECURSE(Visit(expr->left()));
|
| RECURSE(Visit(expr->right()));
|
|
|
| - if (expr->op() == Token::COMMA) {
|
| - current_function_builder_->Emit(kExprEnd);
|
| - }
|
| -
|
| switch (expr->op()) {
|
| BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
|
| BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
|
| @@ -1728,18 +1800,33 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| return (reinterpret_cast<IndexContainer*>(entry->value))->index;
|
| }
|
|
|
| - uint32_t LookupOrInsertFunction(Variable* v) {
|
| + WasmFunctionBuilder* LookupOrInsertFunction(Variable* v) {
|
| DCHECK_NOT_NULL(builder_);
|
| ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
|
| if (entry == nullptr) {
|
| - uint32_t index = builder_->AddFunction();
|
| - IndexContainer* container = new (zone()) IndexContainer();
|
| - container->index = index;
|
| + auto* func_type = typer_->TypeOf(v)->AsFunctionType();
|
| + DCHECK_NOT_NULL(func_type);
|
| + // Build the signature for the function.
|
| + LocalType return_type = TypeFrom(func_type->ReturnType());
|
| + const auto& arguments = func_type->Arguments();
|
| + FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
|
| + arguments.size());
|
| + if (return_type != kAstStmt) b.AddReturn(return_type);
|
| + for (int i = 0; i < static_cast<int>(arguments.size()); ++i) {
|
| + LocalType type = TypeFrom(arguments[i]);
|
| + DCHECK_NE(kAstStmt, type);
|
| + b.AddParam(type);
|
| + }
|
| +
|
| + WasmFunctionBuilder* function = builder_->AddFunction(b.Build());
|
| entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
|
| ZoneAllocationPolicy(zone()));
|
| - entry->value = container;
|
| + function->SetName(
|
| + reinterpret_cast<const char*>(v->raw_name()->raw_data()),
|
| + v->raw_name()->length());
|
| + entry->value = function;
|
| }
|
| - return (reinterpret_cast<IndexContainer*>(entry->value))->index;
|
| + return (reinterpret_cast<WasmFunctionBuilder*>(entry->value));
|
| }
|
|
|
| LocalType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); }
|
| @@ -1774,8 +1861,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
|
| AsmTyper* typer_;
|
| ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
|
| ZoneVector<ForeignVariable> foreign_variables_;
|
| - uint32_t init_function_index_;
|
| - uint32_t foreign_init_function_index_;
|
| + WasmFunctionBuilder* init_function_;
|
| + WasmFunctionBuilder* foreign_init_function_;
|
| uint32_t next_table_index_;
|
| ZoneHashMap function_tables_;
|
| ImportedFunctionTable imported_function_table_;
|
|
|