Chromium Code Reviews| Index: src/asmjs/asm-wasm-builder.cc |
| diff --git a/src/asmjs/asm-wasm-builder.cc b/src/asmjs/asm-wasm-builder.cc |
| index 00e304bbcb76edd7b89d4408b720cd434c9b2161..66b7b8a9244deec6d8641ce6ef0d747668d42f7c 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,29 @@ 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(); |
| + foreign_init_function_->SetExported(); |
| std::string raw_name = "__foreign_init__"; |
| - current_function_builder_->SetName(raw_name.data(), |
| - static_cast<int>(raw_name.size())); |
| - 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 +108,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)); |
|
Mircea Trofin
2016/09/19 16:16:24
Mind changing TypeFrom to taking a const as parame
titzer
2016/09/21 08:58:44
I actually originally did that, but then the const
|
| + 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 +132,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 +164,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 +177,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 +191,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 +226,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 +240,26 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
| breakable_blocks_.pop_back(); |
| } |
| - void VisitContinueStatement(ContinueStatement* stmt) { |
| + void DoBreakOrContinue(BreakableStatement* target, bool is_continue) { |
|
Mircea Trofin
2016/09/19 16:16:24
target could be const
titzer
2016/09/21 08:58:44
The AST is essentially const file-wide, so I think
|
| 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--) { |
|
Mircea Trofin
2016/09/19 16:16:24
--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 +269,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 +285,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 +295,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 +305,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 +319,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++) { |
|
Mircea Trofin
2016/09/19 16:16:24
++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 +351,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--) { |
|
Mircea Trofin
2016/09/19 16:16:24
--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 +375,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 +397,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 +424,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 +439,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 +456,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 +480,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())); |
| @@ -601,11 +622,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()); |
| } |
| } |
| } |
| @@ -613,7 +633,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; |
| } |
| @@ -642,7 +662,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()); |
| } |
| } |
| @@ -672,12 +693,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_; |
| @@ -689,30 +709,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) { |
| @@ -774,7 +815,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) { |
| @@ -783,11 +824,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)); |
| + } |
| } |
| } |
| @@ -799,6 +848,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; |
| @@ -820,6 +870,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) { |
| @@ -828,6 +882,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: |
| @@ -845,7 +903,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()); |
| } |
| @@ -878,7 +936,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> { |
| 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(); |
| } |
| @@ -1103,11 +1161,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)); |
| @@ -1139,13 +1197,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()); |
| @@ -1175,13 +1233,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()); |
| @@ -1267,18 +1325,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) { |
| @@ -1288,22 +1348,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; |
| } |
| @@ -1314,18 +1375,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(); } |
| @@ -1511,16 +1582,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); |
| @@ -1720,18 +1788,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)); } |
| @@ -1766,8 +1849,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_; |