 Chromium Code Reviews
 Chromium Code Reviews Issue 2345593003:
  [wasm] Master CL for Binary 0xC changes.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 2345593003:
  [wasm] Master CL for Binary 0xC changes.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| 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 }; | 
| 
bradnelson
2016/09/23 11:36:00
Delightful name :-)
 | 
| 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_; |