| Index: src/wasm/asm-wasm-builder.cc
 | 
| diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc
 | 
| index f1ccf3db6c8bba7d46631eaa4f10106930fa768d..50b0ea5126e340f8a5201a2c83554c3150e7e793 100644
 | 
| --- a/src/wasm/asm-wasm-builder.cc
 | 
| +++ b/src/wasm/asm-wasm-builder.cc
 | 
| @@ -31,6 +31,7 @@ namespace wasm {
 | 
|      if (HasStackOverflow()) return; \
 | 
|    } while (false)
 | 
|  
 | 
| +enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
 | 
|  
 | 
|  class AsmWasmBuilderImpl : public AstVisitor {
 | 
|   public:
 | 
| @@ -44,9 +45,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          global_variables_(HashMap::PointersMatch,
 | 
|                            ZoneHashMap::kDefaultHashMapCapacity,
 | 
|                            ZoneAllocationPolicy(zone)),
 | 
| -        in_function_(false),
 | 
| -        is_set_op_(false),
 | 
| -        marking_exported(false),
 | 
| +        scope_(kModuleScope),
 | 
|          builder_(new (zone) WasmModuleBuilder(zone)),
 | 
|          current_function_builder_(nullptr),
 | 
|          literal_(literal),
 | 
| @@ -56,7 +55,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          typer_(typer),
 | 
|          cache_(TypeCache::Get()),
 | 
|          breakable_blocks_(zone),
 | 
| -        block_size_(0),
 | 
|          init_function_index_(0),
 | 
|          next_table_index_(0),
 | 
|          function_tables_(HashMap::PointersMatch,
 | 
| @@ -82,13 +80,13 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    void VisitVariableDeclaration(VariableDeclaration* decl) {}
 | 
|  
 | 
|    void VisitFunctionDeclaration(FunctionDeclaration* decl) {
 | 
| -    DCHECK(!in_function_);
 | 
| +    DCHECK_EQ(kModuleScope, scope_);
 | 
|      DCHECK_NULL(current_function_builder_);
 | 
|      uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
 | 
|      current_function_builder_ = builder_->FunctionAt(index);
 | 
| -    in_function_ = true;
 | 
| +    scope_ = kFuncScope;
 | 
|      RECURSE(Visit(decl->fun()));
 | 
| -    in_function_ = false;
 | 
| +    scope_ = kModuleScope;
 | 
|      current_function_builder_ = nullptr;
 | 
|      local_variables_.Clear();
 | 
|    }
 | 
| @@ -102,7 +100,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        Statement* stmt = stmts->at(i);
 | 
|        ExpressionStatement* e = stmt->AsExpressionStatement();
 | 
|        if (e != nullptr && e->expression()->IsUndefinedLiteral()) {
 | 
| -        block_size_--;
 | 
|          continue;
 | 
|        }
 | 
|        RECURSE(Visit(stmt));
 | 
| @@ -121,12 +118,10 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          }
 | 
|        }
 | 
|      }
 | 
| -    if (in_function_) {
 | 
| +    if (scope_ == kFuncScope) {
 | 
|        BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
 | 
| -                           false,
 | 
| -                           static_cast<byte>(stmt->statements()->length()));
 | 
| +                           false);
 | 
|        RECURSE(VisitStatements(stmt->statements()));
 | 
| -      DCHECK(block_size_ >= 0);
 | 
|      } else {
 | 
|        RECURSE(VisitStatements(stmt->statements()));
 | 
|      }
 | 
| @@ -134,25 +129,17 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|  
 | 
|    class BlockVisitor {
 | 
|     private:
 | 
| -    int prev_block_size_;
 | 
| -    uint32_t index_;
 | 
|      AsmWasmBuilderImpl* builder_;
 | 
|  
 | 
|     public:
 | 
|      BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
 | 
| -                 WasmOpcode opcode, bool is_loop, int initial_block_size)
 | 
| +                 WasmOpcode opcode, bool is_loop)
 | 
|          : builder_(builder) {
 | 
|        builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
 | 
|        builder_->current_function_builder_->Emit(opcode);
 | 
| -      index_ =
 | 
| -          builder_->current_function_builder_->EmitEditableVarIntImmediate();
 | 
| -      prev_block_size_ = builder_->block_size_;
 | 
| -      builder_->block_size_ = initial_block_size;
 | 
|      }
 | 
|      ~BlockVisitor() {
 | 
| -      builder_->current_function_builder_->EditVarIntImmediate(
 | 
| -          index_, builder_->block_size_);
 | 
| -      builder_->block_size_ = prev_block_size_;
 | 
| +      builder_->current_function_builder_->Emit(kExprEnd);
 | 
|        builder_->breakable_blocks_.pop_back();
 | 
|      }
 | 
|    };
 | 
| @@ -166,25 +153,24 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
 | 
|  
 | 
|    void VisitIfStatement(IfStatement* stmt) {
 | 
| -    DCHECK(in_function_);
 | 
| -    if (stmt->HasElseStatement()) {
 | 
| -      current_function_builder_->Emit(kExprIfElse);
 | 
| -    } else {
 | 
| -      current_function_builder_->Emit(kExprIf);
 | 
| -    }
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
|      RECURSE(Visit(stmt->condition()));
 | 
| +    current_function_builder_->Emit(kExprIf);
 | 
| +    // WASM ifs come with implement blocks for both arms.
 | 
| +    breakable_blocks_.push_back(std::make_pair(nullptr, false));
 | 
|      if (stmt->HasThenStatement()) {
 | 
|        RECURSE(Visit(stmt->then_statement()));
 | 
| -    } else {
 | 
| -      current_function_builder_->Emit(kExprNop);
 | 
|      }
 | 
|      if (stmt->HasElseStatement()) {
 | 
| +      current_function_builder_->Emit(kExprElse);
 | 
|        RECURSE(Visit(stmt->else_statement()));
 | 
|      }
 | 
| +    current_function_builder_->Emit(kExprEnd);
 | 
| +    breakable_blocks_.pop_back();
 | 
|    }
 | 
|  
 | 
|    void VisitContinueStatement(ContinueStatement* stmt) {
 | 
| -    DCHECK(in_function_);
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
|      DCHECK_NOT_NULL(stmt->target());
 | 
|      int i = static_cast<int>(breakable_blocks_.size()) - 1;
 | 
|      int block_distance = 0;
 | 
| @@ -200,12 +186,13 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        }
 | 
|      }
 | 
|      DCHECK(i >= 0);
 | 
| -    current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
 | 
|      current_function_builder_->Emit(kExprNop);
 | 
| +    current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
 | 
| +    current_function_builder_->EmitVarInt(block_distance);
 | 
|    }
 | 
|  
 | 
|    void VisitBreakStatement(BreakStatement* stmt) {
 | 
| -    DCHECK(in_function_);
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
|      DCHECK_NOT_NULL(stmt->target());
 | 
|      int i = static_cast<int>(breakable_blocks_.size()) - 1;
 | 
|      int block_distance = 0;
 | 
| @@ -223,80 +210,93 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        }
 | 
|      }
 | 
|      DCHECK(i >= 0);
 | 
| -    current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
 | 
|      current_function_builder_->Emit(kExprNop);
 | 
| +    current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
 | 
| +    current_function_builder_->EmitVarInt(block_distance);
 | 
|    }
 | 
|  
 | 
|    void VisitReturnStatement(ReturnStatement* stmt) {
 | 
| -    if (in_function_) {
 | 
| -      current_function_builder_->Emit(kExprReturn);
 | 
| +    if (scope_ == kModuleScope) {
 | 
| +      scope_ = kExportScope;
 | 
| +      RECURSE(Visit(stmt->expression()));
 | 
| +      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);
 | 
|      } else {
 | 
| -      marking_exported = true;
 | 
| -    }
 | 
| -    RECURSE(Visit(stmt->expression()));
 | 
| -    if (!in_function_) {
 | 
| -      marking_exported = false;
 | 
| +      UNREACHABLE();
 | 
|      }
 | 
|    }
 | 
|  
 | 
|    void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
 | 
|  
 | 
| -  void GenerateCaseComparisonCode(int value, WasmOpcode op,
 | 
| -                                  VariableProxy* tag) {
 | 
| -    current_function_builder_->Emit(kExprIfElse);
 | 
| -    current_function_builder_->Emit(op);
 | 
| -    VisitVariableProxy(tag);
 | 
| -    byte code[] = {WASM_I32V(value)};
 | 
| -    current_function_builder_->EmitCode(code, sizeof(code));
 | 
| -  }
 | 
| -
 | 
|    void HandleCase(CaseNode* node,
 | 
|                    const ZoneMap<int, unsigned int>& case_to_block,
 | 
| -                  VariableProxy* tag, int default_block) {
 | 
| +                  VariableProxy* tag, int default_block, int if_depth) {
 | 
| +    int prev_if_depth = if_depth;
 | 
|      if (node->left != nullptr) {
 | 
| -      GenerateCaseComparisonCode(node->begin, kExprI32LtS, tag);
 | 
| -      HandleCase(node->left, case_to_block, tag, default_block);
 | 
| +      VisitVariableProxy(tag);
 | 
| +      current_function_builder_->EmitI32Const(node->begin);
 | 
| +      current_function_builder_->Emit(kExprI32LtS);
 | 
| +      current_function_builder_->Emit(kExprIf);
 | 
| +      if_depth++;
 | 
| +      breakable_blocks_.push_back(std::make_pair(nullptr, false));
 | 
| +      HandleCase(node->left, case_to_block, tag, default_block, if_depth);
 | 
| +      current_function_builder_->Emit(kExprElse);
 | 
|      }
 | 
|      if (node->right != nullptr) {
 | 
| -      GenerateCaseComparisonCode(node->end, kExprI32GtS, tag);
 | 
| -      HandleCase(node->right, case_to_block, tag, default_block);
 | 
| +      VisitVariableProxy(tag);
 | 
| +      current_function_builder_->EmitI32Const(node->end);
 | 
| +      current_function_builder_->Emit(kExprI32GtS);
 | 
| +      current_function_builder_->Emit(kExprIf);
 | 
| +      if_depth++;
 | 
| +      breakable_blocks_.push_back(std::make_pair(nullptr, false));
 | 
| +      HandleCase(node->right, case_to_block, tag, default_block, if_depth);
 | 
| +      current_function_builder_->Emit(kExprElse);
 | 
|      }
 | 
|      if (node->begin == node->end) {
 | 
| -      current_function_builder_->Emit(kExprIf);
 | 
| -      current_function_builder_->Emit(kExprI32Eq);
 | 
|        VisitVariableProxy(tag);
 | 
| -      byte code[] = {WASM_I32V(node->begin)};
 | 
| -      current_function_builder_->EmitCode(code, sizeof(code));
 | 
| +      current_function_builder_->EmitI32Const(node->begin);
 | 
| +      current_function_builder_->Emit(kExprI32Eq);
 | 
| +      current_function_builder_->Emit(kExprIf);
 | 
|        DCHECK(case_to_block.find(node->begin) != case_to_block.end());
 | 
| -      current_function_builder_->EmitWithVarInt(kExprBr,
 | 
| -                                                case_to_block.at(node->begin));
 | 
|        current_function_builder_->Emit(kExprNop);
 | 
| +      current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
 | 
| +      current_function_builder_->EmitVarInt(1 + if_depth +
 | 
| +                                            case_to_block.at(node->begin));
 | 
| +      current_function_builder_->Emit(kExprEnd);
 | 
|      } else {
 | 
| -      current_function_builder_->Emit(kExprBrTable);
 | 
| +      current_function_builder_->Emit(kExprNop);
 | 
| +      if (node->begin != 0) {
 | 
| +        VisitVariableProxy(tag);
 | 
| +        current_function_builder_->EmitI32Const(node->begin);
 | 
| +        current_function_builder_->Emit(kExprI32Sub);
 | 
| +      } else {
 | 
| +        VisitVariableProxy(tag);
 | 
| +      }
 | 
| +      current_function_builder_->EmitWithU8(kExprBrTable, ARITY_0);
 | 
|        current_function_builder_->EmitVarInt(node->end - node->begin + 1);
 | 
|        for (int v = node->begin; v <= node->end; v++) {
 | 
|          if (case_to_block.find(v) != case_to_block.end()) {
 | 
| -          byte break_code[] = {BR_TARGET(case_to_block.at(v))};
 | 
| +          byte break_code[] = {BR_TARGET(if_depth + case_to_block.at(v))};
 | 
|            current_function_builder_->EmitCode(break_code, sizeof(break_code));
 | 
|          } else {
 | 
| -          byte break_code[] = {BR_TARGET(default_block)};
 | 
| +          byte break_code[] = {BR_TARGET(if_depth + default_block)};
 | 
|            current_function_builder_->EmitCode(break_code, sizeof(break_code));
 | 
|          }
 | 
|          if (v == kMaxInt) {
 | 
|            break;
 | 
|          }
 | 
|        }
 | 
| -      byte break_code[] = {BR_TARGET(default_block)};
 | 
| +      byte break_code[] = {BR_TARGET(if_depth + default_block)};
 | 
|        current_function_builder_->EmitCode(break_code, sizeof(break_code));
 | 
| -      // TODO(aseemgarg): remove the if once sub 0 is fixed
 | 
| -      if (node->begin != 0) {
 | 
| -        current_function_builder_->Emit(kExprI32Sub);
 | 
| -        VisitVariableProxy(tag);
 | 
| -        byte code[] = {WASM_I32V(node->begin)};
 | 
| -        current_function_builder_->EmitCode(code, sizeof(code));
 | 
| -      } else {
 | 
| -        VisitVariableProxy(tag);
 | 
| -      }
 | 
| +    }
 | 
| +
 | 
| +    while (if_depth-- != prev_if_depth) {
 | 
| +      breakable_blocks_.pop_back();
 | 
| +      current_function_builder_->Emit(kExprEnd);
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -306,19 +306,16 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|      ZoneList<CaseClause*>* clauses = stmt->cases();
 | 
|      int case_count = clauses->length();
 | 
|      if (case_count == 0) {
 | 
| -      block_size_--;
 | 
|        return;
 | 
|      }
 | 
| -    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
 | 
| -                         1);
 | 
| +    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false);
 | 
|      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--) {
 | 
|        CaseClause* clause = clauses->at(i);
 | 
| -      blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false,
 | 
| -                                        clause->statements()->length() + 1));
 | 
| +      blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false));
 | 
|        if (!clause->is_default()) {
 | 
|          Literal* label = clause->label()->AsLiteral();
 | 
|          Handle<Object> value = label->value();
 | 
| @@ -337,17 +334,15 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|      }
 | 
|      if (!has_default || case_count > 1) {
 | 
|        int default_block = has_default ? case_count - 1 : case_count;
 | 
| -      BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false, 1);
 | 
| +      BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false);
 | 
|        CaseNode* root = OrderCases(&cases, zone_);
 | 
| -      HandleCase(root, case_to_block, tag, default_block);
 | 
| +      HandleCase(root, case_to_block, tag, default_block, 0);
 | 
|        if (root->left != nullptr || root->right != nullptr ||
 | 
|            root->begin == root->end) {
 | 
| -        block_size_++;
 | 
| -        current_function_builder_->EmitWithVarInt(kExprBr, default_block);
 | 
| +        current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
 | 
| +        current_function_builder_->EmitVarInt(default_block);
 | 
|          current_function_builder_->Emit(kExprNop);
 | 
|        }
 | 
| -    } else {
 | 
| -      block_size_ = clauses->at(0)->statements()->length();
 | 
|      }
 | 
|      for (int i = 0; i < case_count; i++) {
 | 
|        CaseClause* clause = clauses->at(i);
 | 
| @@ -361,53 +356,49 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
 | 
|  
 | 
|    void VisitDoWhileStatement(DoWhileStatement* stmt) {
 | 
| -    DCHECK(in_function_);
 | 
| -    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
 | 
| -                         2);
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
| +    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
 | 
|      RECURSE(Visit(stmt->body()));
 | 
| -    current_function_builder_->Emit(kExprIf);
 | 
|      RECURSE(Visit(stmt->cond()));
 | 
| -    current_function_builder_->EmitWithVarInt(kExprBr, 0);
 | 
| -    current_function_builder_->Emit(kExprNop);
 | 
| +    current_function_builder_->Emit(kExprIf);
 | 
| +    current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
 | 
| +    current_function_builder_->Emit(kExprEnd);
 | 
|    }
 | 
|  
 | 
|    void VisitWhileStatement(WhileStatement* stmt) {
 | 
| -    DCHECK(in_function_);
 | 
| -    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
 | 
| -                         1);
 | 
| -    current_function_builder_->Emit(kExprIf);
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
| +    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
 | 
|      RECURSE(Visit(stmt->cond()));
 | 
| -    current_function_builder_->EmitWithVarInt(kExprBr, 0);
 | 
| +    breakable_blocks_.push_back(std::make_pair(nullptr, false));
 | 
| +    current_function_builder_->Emit(kExprIf);
 | 
|      RECURSE(Visit(stmt->body()));
 | 
| +    current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
 | 
| +    current_function_builder_->Emit(kExprEnd);
 | 
| +    breakable_blocks_.pop_back();
 | 
|    }
 | 
|  
 | 
|    void VisitForStatement(ForStatement* stmt) {
 | 
| -    DCHECK(in_function_);
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
|      if (stmt->init() != nullptr) {
 | 
| -      block_size_++;
 | 
|        RECURSE(Visit(stmt->init()));
 | 
|      }
 | 
| -    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
 | 
| -                         0);
 | 
| +    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
 | 
|      if (stmt->cond() != nullptr) {
 | 
| -      block_size_++;
 | 
| -      current_function_builder_->Emit(kExprIf);
 | 
| -      current_function_builder_->Emit(kExprI32Eqz);
 | 
|        RECURSE(Visit(stmt->cond()));
 | 
| -      current_function_builder_->EmitWithVarInt(kExprBr, 1);
 | 
| +      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_->Emit(kExprEnd);
 | 
|      }
 | 
|      if (stmt->body() != nullptr) {
 | 
| -      block_size_++;
 | 
|        RECURSE(Visit(stmt->body()));
 | 
|      }
 | 
|      if (stmt->next() != nullptr) {
 | 
| -      block_size_++;
 | 
|        RECURSE(Visit(stmt->next()));
 | 
|      }
 | 
| -    block_size_++;
 | 
| -    current_function_builder_->EmitWithVarInt(kExprBr, 0);
 | 
|      current_function_builder_->Emit(kExprNop);
 | 
| +    current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
 | 
|    }
 | 
|  
 | 
|    void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
 | 
| @@ -422,7 +413,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|  
 | 
|    void VisitFunctionLiteral(FunctionLiteral* expr) {
 | 
|      Scope* scope = expr->scope();
 | 
| -    if (in_function_) {
 | 
| +    if (scope_ == kFuncScope) {
 | 
|        if (expr->bounds().lower->IsFunction()) {
 | 
|          FunctionType* func_type = expr->bounds().lower->AsFunction();
 | 
|          LocalType return_type = TypeFrom(func_type->Result());
 | 
| @@ -445,11 +436,16 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    }
 | 
|  
 | 
|    void VisitConditional(Conditional* expr) {
 | 
| -    DCHECK(in_function_);
 | 
| -    current_function_builder_->Emit(kExprIfElse);
 | 
| +    DCHECK_EQ(kFuncScope, scope_);
 | 
|      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);
 | 
|      RECURSE(Visit(expr->then_expression()));
 | 
| +    current_function_builder_->Emit(kExprElse);
 | 
|      RECURSE(Visit(expr->else_expression()));
 | 
| +    current_function_builder_->Emit(kExprEnd);
 | 
| +    breakable_blocks_.pop_back();
 | 
|    }
 | 
|  
 | 
|    bool VisitStdlibConstant(Variable* var) {
 | 
| @@ -505,36 +501,26 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    }
 | 
|  
 | 
|    void VisitVariableProxy(VariableProxy* expr) {
 | 
| -    if (in_function_) {
 | 
| +    if (scope_ == kFuncScope || scope_ == kInitScope) {
 | 
|        Variable* var = expr->var();
 | 
| +      if (VisitStdlibConstant(var)) {
 | 
| +        return;
 | 
| +      }
 | 
|        LocalType var_type = TypeOf(expr);
 | 
| -      if (is_set_op_) {
 | 
| -        is_set_op_ = false;
 | 
| -        if (var->IsContextSlot()) {
 | 
| -          return current_function_builder_->EmitWithVarInt(
 | 
| -              kExprStoreGlobal, LookupOrInsertGlobal(var, var_type));
 | 
| -        } else {
 | 
| -          return current_function_builder_->EmitSetLocal(
 | 
| -              LookupOrInsertLocal(var, var_type));
 | 
| -        }
 | 
| +      DCHECK_NE(kAstStmt, var_type);
 | 
| +      if (var->IsContextSlot()) {
 | 
| +        current_function_builder_->EmitWithVarInt(
 | 
| +            kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
 | 
|        } else {
 | 
| -        if (VisitStdlibConstant(var)) {
 | 
| -          return;
 | 
| -        }
 | 
| -        if (var->IsContextSlot()) {
 | 
| -          return current_function_builder_->EmitWithVarInt(
 | 
| -              kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
 | 
| -        } else {
 | 
| -          return current_function_builder_->EmitGetLocal(
 | 
| -              LookupOrInsertLocal(var, var_type));
 | 
| -        }
 | 
| +        current_function_builder_->EmitGetLocal(
 | 
| +            LookupOrInsertLocal(var, var_type));
 | 
|        }
 | 
|      }
 | 
|    }
 | 
|  
 | 
|    void VisitLiteral(Literal* expr) {
 | 
|      Handle<Object> value = expr->value();
 | 
| -    if (!in_function_ || !value->IsNumber()) {
 | 
| +    if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
 | 
|        return;
 | 
|      }
 | 
|      Type* type = expr->bounds().upper;
 | 
| @@ -568,7 +554,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|      ZoneList<ObjectLiteralProperty*>* props = expr->properties();
 | 
|      for (int i = 0; i < props->length(); ++i) {
 | 
|        ObjectLiteralProperty* prop = props->at(i);
 | 
| -      DCHECK(marking_exported);
 | 
| +      DCHECK_EQ(kExportScope, scope_);
 | 
|        VariableProxy* expr = prop->value()->AsVariableProxy();
 | 
|        DCHECK_NOT_NULL(expr);
 | 
|        Variable* var = expr->var();
 | 
| @@ -589,11 +575,11 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|  
 | 
|    void LoadInitFunction() {
 | 
|      current_function_builder_ = builder_->FunctionAt(init_function_index_);
 | 
| -    in_function_ = true;
 | 
| +    scope_ = kInitScope;
 | 
|    }
 | 
|  
 | 
|    void UnLoadInitFunction() {
 | 
| -    in_function_ = false;
 | 
| +    scope_ = kModuleScope;
 | 
|      current_function_builder_ = nullptr;
 | 
|    }
 | 
|  
 | 
| @@ -696,33 +682,98 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|      }
 | 
|    };
 | 
|  
 | 
| -  void VisitAssignment(Assignment* expr) {
 | 
| -    bool in_init = false;
 | 
| -    if (!in_function_) {
 | 
| -      BinaryOperation* binop = expr->value()->AsBinaryOperation();
 | 
| -      if (binop != nullptr) {
 | 
| +  void EmitAssignmentLhs(Expression* target, MachineType* mtype) {
 | 
| +    // Match the left hand side of the assignment.
 | 
| +    VariableProxy* target_var = target->AsVariableProxy();
 | 
| +    if (target_var != nullptr) {
 | 
| +      // Left hand side is a local or a global variable, no code on LHS.
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    Property* target_prop = target->AsProperty();
 | 
| +    if (target_prop != nullptr) {
 | 
| +      // Left hand side is a property access, i.e. the asm.js heap.
 | 
| +      VisitPropertyAndEmitIndex(target_prop, mtype);
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    if (target_var == nullptr && target_prop == nullptr) {
 | 
| +      UNREACHABLE();  // invalid assignment.
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) {
 | 
| +    BinaryOperation* binop = value->AsBinaryOperation();
 | 
| +    if (binop != nullptr) {
 | 
| +      if (scope_ == kInitScope) {
 | 
| +        // Handle foreign variables in the initialization scope.
 | 
|          Property* prop = binop->left()->AsProperty();
 | 
| -        DCHECK_NOT_NULL(prop);
 | 
| -        LoadInitFunction();
 | 
| -        is_set_op_ = true;
 | 
| -        RECURSE(Visit(expr->target()));
 | 
| -        DCHECK(!is_set_op_);
 | 
|          if (binop->op() == Token::MUL) {
 | 
|            DCHECK(binop->right()->IsLiteral());
 | 
|            DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
 | 
|            DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
 | 
|            VisitForeignVariable(true, prop);
 | 
| +          return;
 | 
|          } else if (binop->op() == Token::BIT_OR) {
 | 
|            DCHECK(binop->right()->IsLiteral());
 | 
|            DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
 | 
|            DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
 | 
|            VisitForeignVariable(false, prop);
 | 
| +          return;
 | 
|          } else {
 | 
|            UNREACHABLE();
 | 
|          }
 | 
| -        UnLoadInitFunction();
 | 
| -        return;
 | 
|        }
 | 
| +      if (MatchBinaryOperation(binop) == kAsIs) {
 | 
| +        VariableProxy* target_var = target->AsVariableProxy();
 | 
| +        VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy();
 | 
| +        if (target_var != nullptr && effective_value_var != nullptr &&
 | 
| +            target_var->var() == effective_value_var->var()) {
 | 
| +          *is_nop = true;
 | 
| +          return;
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +    RECURSE(Visit(value));
 | 
| +  }
 | 
| +
 | 
| +  void EmitAssignment(Assignment* expr, MachineType mtype) {
 | 
| +    // Match the left hand side of the assignment.
 | 
| +    VariableProxy* target_var = expr->target()->AsVariableProxy();
 | 
| +    if (target_var != nullptr) {
 | 
| +      // Left hand side is a local or a global variable.
 | 
| +      Variable* var = target_var->var();
 | 
| +      LocalType var_type = TypeOf(expr);
 | 
| +      DCHECK_NE(kAstStmt, var_type);
 | 
| +      if (var->IsContextSlot()) {
 | 
| +        current_function_builder_->EmitWithVarInt(
 | 
| +            kExprStoreGlobal, LookupOrInsertGlobal(var, var_type));
 | 
| +      } else {
 | 
| +        current_function_builder_->EmitSetLocal(
 | 
| +            LookupOrInsertLocal(var, var_type));
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    Property* target_prop = expr->target()->AsProperty();
 | 
| +    if (target_prop != nullptr) {
 | 
| +      // Left hand side is a property access, i.e. the asm.js heap.
 | 
| +      if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
 | 
| +          expr->target()->AsProperty()->obj()->bounds().lower->Is(
 | 
| +              cache_.kFloat32Array)) {
 | 
| +        current_function_builder_->Emit(kExprF32ConvertF64);
 | 
| +      }
 | 
| +      current_function_builder_->EmitWithU8U8(
 | 
| +          WasmOpcodes::LoadStoreOpcodeOf(mtype, true), 0, 0);
 | 
| +    }
 | 
| +
 | 
| +    if (target_var == nullptr && target_prop == nullptr) {
 | 
| +      UNREACHABLE();  // invalid assignment.
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void VisitAssignment(Assignment* expr) {
 | 
| +    bool as_init = false;
 | 
| +    if (scope_ == kModuleScope) {
 | 
|        Property* prop = expr->value()->AsProperty();
 | 
|        if (prop != nullptr) {
 | 
|          VariableProxy* vp = prop->obj()->AsVariableProxy();
 | 
| @@ -752,32 +803,18 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          // No init code to emit for CallNew nodes.
 | 
|          return;
 | 
|        }
 | 
| -      in_init = true;
 | 
| -      LoadInitFunction();
 | 
| -    }
 | 
| -    BinaryOperation* value_op = expr->value()->AsBinaryOperation();
 | 
| -    if (value_op != nullptr && MatchBinaryOperation(value_op) == kAsIs) {
 | 
| -      VariableProxy* target_var = expr->target()->AsVariableProxy();
 | 
| -      VariableProxy* effective_value_var = GetLeft(value_op)->AsVariableProxy();
 | 
| -      if (target_var != nullptr && effective_value_var != nullptr &&
 | 
| -          target_var->var() == effective_value_var->var()) {
 | 
| -        block_size_--;
 | 
| -        return;
 | 
| -      }
 | 
| -    }
 | 
| -    is_set_op_ = true;
 | 
| -    RECURSE(Visit(expr->target()));
 | 
| -    DCHECK(!is_set_op_);
 | 
| -    // Assignment to heapf32 from float64 converts.
 | 
| -    if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
 | 
| -        expr->target()->AsProperty()->obj()->bounds().lower->Is(
 | 
| -            cache_.kFloat32Array)) {
 | 
| -      current_function_builder_->Emit(kExprF32ConvertF64);
 | 
| +      as_init = true;
 | 
|      }
 | 
| -    RECURSE(Visit(expr->value()));
 | 
| -    if (in_init) {
 | 
| -      UnLoadInitFunction();
 | 
| +
 | 
| +    if (as_init) LoadInitFunction();
 | 
| +    MachineType mtype;
 | 
| +    bool is_nop = false;
 | 
| +    EmitAssignmentLhs(expr->target(), &mtype);
 | 
| +    EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
 | 
| +    if (!is_nop) {
 | 
| +      EmitAssignment(expr, mtype);
 | 
|      }
 | 
| +    if (as_init) UnLoadInitFunction();
 | 
|    }
 | 
|  
 | 
|    void VisitYield(Yield* expr) { UNREACHABLE(); }
 | 
| @@ -816,9 +853,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|              Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
 | 
|              if (nvalue->IsNumber()) {
 | 
|                int32_t val = static_cast<int32_t>(nvalue->Number());
 | 
| -              // TODO(bradnelson): variable size
 | 
| -              byte code[] = {WASM_I32V(val)};
 | 
| -              current_function_builder_->EmitCode(code, sizeof(code));
 | 
| +              current_function_builder_->EmitI32Const(val);
 | 
|                return;
 | 
|              }
 | 
|            }
 | 
| @@ -834,46 +869,41 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|      }
 | 
|    }
 | 
|  
 | 
| -  void VisitProperty(Property* expr) {
 | 
| +  void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
 | 
|      Expression* obj = expr->obj();
 | 
|      DCHECK_EQ(obj->bounds().lower, obj->bounds().upper);
 | 
|      Type* type = obj->bounds().lower;
 | 
| -    MachineType mtype;
 | 
|      int size;
 | 
|      if (type->Is(cache_.kUint8Array)) {
 | 
| -      mtype = MachineType::Uint8();
 | 
| +      *mtype = MachineType::Uint8();
 | 
|        size = 1;
 | 
|      } else if (type->Is(cache_.kInt8Array)) {
 | 
| -      mtype = MachineType::Int8();
 | 
| +      *mtype = MachineType::Int8();
 | 
|        size = 1;
 | 
|      } else if (type->Is(cache_.kUint16Array)) {
 | 
| -      mtype = MachineType::Uint16();
 | 
| +      *mtype = MachineType::Uint16();
 | 
|        size = 2;
 | 
|      } else if (type->Is(cache_.kInt16Array)) {
 | 
| -      mtype = MachineType::Int16();
 | 
| +      *mtype = MachineType::Int16();
 | 
|        size = 2;
 | 
|      } else if (type->Is(cache_.kUint32Array)) {
 | 
| -      mtype = MachineType::Uint32();
 | 
| +      *mtype = MachineType::Uint32();
 | 
|        size = 4;
 | 
|      } else if (type->Is(cache_.kInt32Array)) {
 | 
| -      mtype = MachineType::Int32();
 | 
| +      *mtype = MachineType::Int32();
 | 
|        size = 4;
 | 
|      } else if (type->Is(cache_.kUint32Array)) {
 | 
| -      mtype = MachineType::Uint32();
 | 
| +      *mtype = MachineType::Uint32();
 | 
|        size = 4;
 | 
|      } else if (type->Is(cache_.kFloat32Array)) {
 | 
| -      mtype = MachineType::Float32();
 | 
| +      *mtype = MachineType::Float32();
 | 
|        size = 4;
 | 
|      } else if (type->Is(cache_.kFloat64Array)) {
 | 
| -      mtype = MachineType::Float64();
 | 
| +      *mtype = MachineType::Float64();
 | 
|        size = 8;
 | 
|      } else {
 | 
|        UNREACHABLE();
 | 
|      }
 | 
| -    // TODO(titzer): use special asm-compatibility opcodes?
 | 
| -    current_function_builder_->EmitWithU8U8(
 | 
| -        WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_), 0, 0);
 | 
| -    is_set_op_ = false;
 | 
|      if (size == 1) {
 | 
|        // Allow more general expression in byte arrays than the spec
 | 
|        // strictly permits.
 | 
| @@ -881,87 +911,103 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        // places that strictly should be HEAP8[HEAP32[..]>>0].
 | 
|        RECURSE(Visit(expr->key()));
 | 
|        return;
 | 
| -    } else {
 | 
| -      Literal* value = expr->key()->AsLiteral();
 | 
| -      if (value) {
 | 
| -        DCHECK(value->raw_value()->IsNumber());
 | 
| -        DCHECK_EQ(kAstI32, TypeOf(value));
 | 
| -        int val = static_cast<int>(value->raw_value()->AsNumber());
 | 
| -        // TODO(bradnelson): variable size
 | 
| -        byte code[] = {WASM_I32V(val * size)};
 | 
| -        current_function_builder_->EmitCode(code, sizeof(code));
 | 
| -        return;
 | 
| -      }
 | 
| -      BinaryOperation* binop = expr->key()->AsBinaryOperation();
 | 
| -      if (binop) {
 | 
| -        DCHECK_EQ(Token::SAR, binop->op());
 | 
| -        DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
 | 
| -        DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
 | 
| -        DCHECK_EQ(size,
 | 
| -                  1 << static_cast<int>(
 | 
| -                      binop->right()->AsLiteral()->raw_value()->AsNumber()));
 | 
| -        // Mask bottom bits to match asm.js behavior.
 | 
| -        current_function_builder_->Emit(kExprI32And);
 | 
| -        byte code[] = {WASM_I8(~(size - 1))};
 | 
| -        current_function_builder_->EmitCode(code, sizeof(code));
 | 
| -        RECURSE(Visit(binop->left()));
 | 
| -        return;
 | 
| -      }
 | 
| +    }
 | 
| +
 | 
| +    Literal* value = expr->key()->AsLiteral();
 | 
| +    if (value) {
 | 
| +      DCHECK(value->raw_value()->IsNumber());
 | 
| +      DCHECK_EQ(kAstI32, TypeOf(value));
 | 
| +      int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber());
 | 
| +      // TODO(titzer): handle overflow here.
 | 
| +      current_function_builder_->EmitI32Const(val * size);
 | 
| +      return;
 | 
| +    }
 | 
| +    BinaryOperation* binop = expr->key()->AsBinaryOperation();
 | 
| +    if (binop) {
 | 
| +      DCHECK_EQ(Token::SAR, binop->op());
 | 
| +      DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
 | 
| +      DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
 | 
| +      DCHECK_EQ(size,
 | 
| +                1 << static_cast<int>(
 | 
| +                    binop->right()->AsLiteral()->raw_value()->AsNumber()));
 | 
| +      // Mask bottom bits to match asm.js behavior.
 | 
| +      byte mask = static_cast<byte>(~(size - 1));
 | 
| +      RECURSE(Visit(binop->left()));
 | 
| +      current_function_builder_->EmitWithU8(kExprI8Const, mask);
 | 
| +      current_function_builder_->Emit(kExprI32And);
 | 
| +      return;
 | 
|      }
 | 
|      UNREACHABLE();
 | 
|    }
 | 
|  
 | 
| +  void VisitProperty(Property* expr) {
 | 
| +    MachineType mtype;
 | 
| +    VisitPropertyAndEmitIndex(expr, &mtype);
 | 
| +    current_function_builder_->EmitWithU8U8(
 | 
| +        WasmOpcodes::LoadStoreOpcodeOf(mtype, false), 0, 0);
 | 
| +  }
 | 
| +
 | 
|    bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
 | 
|      Variable* var = expr->var();
 | 
|      AsmTyper::StandardMember standard_object =
 | 
|          typer_->VariableAsStandardMember(var);
 | 
|      ZoneList<Expression*>* args = call->arguments();
 | 
|      LocalType call_type = TypeOf(call);
 | 
| +
 | 
|      switch (standard_object) {
 | 
|        case AsmTyper::kNone: {
 | 
|          return false;
 | 
|        }
 | 
|        case AsmTyper::kMathAcos: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Acos);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathAsin: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Asin);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathAtan: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Atan);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathCos: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Cos);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathSin: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Sin);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathTan: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Tan);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathExp: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Exp);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathLog: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Log);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathCeil: {
 | 
| +        VisitCallArgs(call);
 | 
|          if (call_type == kAstF32) {
 | 
|            current_function_builder_->Emit(kExprF32Ceil);
 | 
|          } else if (call_type == kAstF64) {
 | 
| @@ -972,6 +1018,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathFloor: {
 | 
| +        VisitCallArgs(call);
 | 
|          if (call_type == kAstF32) {
 | 
|            current_function_builder_->Emit(kExprF32Floor);
 | 
|          } else if (call_type == kAstF64) {
 | 
| @@ -982,6 +1029,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathSqrt: {
 | 
| +        VisitCallArgs(call);
 | 
|          if (call_type == kAstF32) {
 | 
|            current_function_builder_->Emit(kExprF32Sqrt);
 | 
|          } else if (call_type == kAstF64) {
 | 
| @@ -992,19 +1040,33 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathAbs: {
 | 
| -        // TODO(bradnelson): Should this be cast to float?
 | 
|          if (call_type == kAstI32) {
 | 
| -          current_function_builder_->Emit(kExprIfElse);
 | 
| -          current_function_builder_->Emit(kExprI32LtS);
 | 
| -          Visit(args->at(0));
 | 
| +          uint16_t tmp = current_function_builder_->AddLocal(kAstI32);
 | 
| +
 | 
| +          // if set_local(tmp, x) < 0
 | 
| +          Visit(call->arguments()->at(0));
 | 
| +          current_function_builder_->EmitSetLocal(tmp);
 | 
|            byte code[] = {WASM_I8(0)};
 | 
|            current_function_builder_->EmitCode(code, sizeof(code));
 | 
| -          current_function_builder_->Emit(kExprI32Sub);
 | 
| +          current_function_builder_->Emit(kExprI32LtS);
 | 
| +          current_function_builder_->Emit(kExprIf);
 | 
| +
 | 
| +          // then (0 - tmp)
 | 
|            current_function_builder_->EmitCode(code, sizeof(code));
 | 
| -          Visit(args->at(0));
 | 
| +          current_function_builder_->EmitGetLocal(tmp);
 | 
| +          current_function_builder_->Emit(kExprI32Sub);
 | 
| +
 | 
| +          // else tmp
 | 
| +          current_function_builder_->Emit(kExprElse);
 | 
| +          current_function_builder_->EmitGetLocal(tmp);
 | 
| +          // end
 | 
| +          current_function_builder_->Emit(kExprEnd);
 | 
| +
 | 
|          } else if (call_type == kAstF32) {
 | 
| +          VisitCallArgs(call);
 | 
|            current_function_builder_->Emit(kExprF32Abs);
 | 
|          } else if (call_type == kAstF64) {
 | 
| +          VisitCallArgs(call);
 | 
|            current_function_builder_->Emit(kExprF64Abs);
 | 
|          } else {
 | 
|            UNREACHABLE();
 | 
| @@ -1014,13 +1076,32 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        case AsmTyper::kMathMin: {
 | 
|          // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
 | 
|          if (call_type == kAstI32) {
 | 
| -          current_function_builder_->Emit(kExprIfElse);
 | 
| +          uint16_t tmp_x = current_function_builder_->AddLocal(kAstI32);
 | 
| +          uint16_t tmp_y = current_function_builder_->AddLocal(kAstI32);
 | 
| +
 | 
| +          // if set_local(tmp_x, x) < set_local(tmp_y, y)
 | 
| +          Visit(call->arguments()->at(0));
 | 
| +          current_function_builder_->EmitSetLocal(tmp_x);
 | 
| +
 | 
| +          Visit(call->arguments()->at(1));
 | 
| +          current_function_builder_->EmitSetLocal(tmp_y);
 | 
| +
 | 
|            current_function_builder_->Emit(kExprI32LeS);
 | 
| -          Visit(args->at(0));
 | 
| -          Visit(args->at(1));
 | 
| +          current_function_builder_->Emit(kExprIf);
 | 
| +
 | 
| +          // then tmp_x
 | 
| +          current_function_builder_->EmitGetLocal(tmp_x);
 | 
| +
 | 
| +          // else tmp_y
 | 
| +          current_function_builder_->Emit(kExprElse);
 | 
| +          current_function_builder_->EmitGetLocal(tmp_y);
 | 
| +          current_function_builder_->Emit(kExprEnd);
 | 
| +
 | 
|          } else if (call_type == kAstF32) {
 | 
| +          VisitCallArgs(call);
 | 
|            current_function_builder_->Emit(kExprF32Min);
 | 
|          } else if (call_type == kAstF64) {
 | 
| +          VisitCallArgs(call);
 | 
|            current_function_builder_->Emit(kExprF64Min);
 | 
|          } else {
 | 
|            UNREACHABLE();
 | 
| @@ -1030,13 +1111,33 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        case AsmTyper::kMathMax: {
 | 
|          // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
 | 
|          if (call_type == kAstI32) {
 | 
| -          current_function_builder_->Emit(kExprIfElse);
 | 
| -          current_function_builder_->Emit(kExprI32GtS);
 | 
| -          Visit(args->at(0));
 | 
| -          Visit(args->at(1));
 | 
| +          uint16_t tmp_x = current_function_builder_->AddLocal(kAstI32);
 | 
| +          uint16_t tmp_y = current_function_builder_->AddLocal(kAstI32);
 | 
| +
 | 
| +          // if set_local(tmp_x, x) < set_local(tmp_y, y)
 | 
| +          Visit(call->arguments()->at(0));
 | 
| +
 | 
| +          current_function_builder_->EmitSetLocal(tmp_x);
 | 
| +
 | 
| +          Visit(call->arguments()->at(1));
 | 
| +          current_function_builder_->EmitSetLocal(tmp_y);
 | 
| +
 | 
| +          current_function_builder_->Emit(kExprI32LeS);
 | 
| +          current_function_builder_->Emit(kExprIf);
 | 
| +
 | 
| +          // then tmp_y
 | 
| +          current_function_builder_->EmitGetLocal(tmp_y);
 | 
| +
 | 
| +          // else tmp_x
 | 
| +          current_function_builder_->Emit(kExprElse);
 | 
| +          current_function_builder_->EmitGetLocal(tmp_x);
 | 
| +          current_function_builder_->Emit(kExprEnd);
 | 
| +
 | 
|          } else if (call_type == kAstF32) {
 | 
| +          VisitCallArgs(call);
 | 
|            current_function_builder_->Emit(kExprF32Max);
 | 
|          } else if (call_type == kAstF64) {
 | 
| +          VisitCallArgs(call);
 | 
|            current_function_builder_->Emit(kExprF64Max);
 | 
|          } else {
 | 
|            UNREACHABLE();
 | 
| @@ -1044,16 +1145,19 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathAtan2: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Atan2);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathPow: {
 | 
| +        VisitCallArgs(call);
 | 
|          DCHECK_EQ(kAstF64, call_type);
 | 
|          current_function_builder_->Emit(kExprF64Pow);
 | 
|          break;
 | 
|        }
 | 
|        case AsmTyper::kMathImul: {
 | 
| +        VisitCallArgs(call);
 | 
|          current_function_builder_->Emit(kExprI32Mul);
 | 
|          break;
 | 
|        }
 | 
| @@ -1061,6 +1165,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          DCHECK(args->length() == 1);
 | 
|          Literal* literal = args->at(0)->AsLiteral();
 | 
|          if (literal != nullptr) {
 | 
| +          // constant fold Math.fround(#const);
 | 
|            if (literal->raw_value()->IsNumber()) {
 | 
|              float val = static_cast<float>(literal->raw_value()->AsNumber());
 | 
|              byte code[] = {WASM_F32(val)};
 | 
| @@ -1068,6 +1173,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|              return true;
 | 
|            }
 | 
|          }
 | 
| +        VisitCallArgs(call);
 | 
|          switch (TypeIndexOf(args->at(0))) {
 | 
|            case kInt32:
 | 
|            case kFixnum:
 | 
| @@ -1091,7 +1197,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          break;
 | 
|        }
 | 
|      }
 | 
| -    VisitCallArgs(call);
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| @@ -1107,7 +1212,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|      Call::CallType call_type = expr->GetCallType(isolate_);
 | 
|      switch (call_type) {
 | 
|        case Call::OTHER_CALL: {
 | 
| -        DCHECK(in_function_);
 | 
| +        DCHECK_EQ(kFuncScope, scope_);
 | 
|          VariableProxy* proxy = expr->expression()->AsVariableProxy();
 | 
|          if (proxy != nullptr) {
 | 
|            if (VisitStdlibFunction(expr, proxy)) {
 | 
| @@ -1133,30 +1238,31 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|          } else {
 | 
|            index = LookupOrInsertFunction(vp->var());
 | 
|          }
 | 
| +        VisitCallArgs(expr);
 | 
|          current_function_builder_->Emit(kExprCallFunction);
 | 
| +        current_function_builder_->EmitVarInt(expr->arguments()->length());
 | 
|          current_function_builder_->EmitVarInt(index);
 | 
|          break;
 | 
|        }
 | 
|        case Call::KEYED_PROPERTY_CALL: {
 | 
| -        DCHECK(in_function_);
 | 
| +        DCHECK_EQ(kFuncScope, scope_);
 | 
|          Property* p = expr->expression()->AsProperty();
 | 
|          DCHECK_NOT_NULL(p);
 | 
|          VariableProxy* var = p->obj()->AsVariableProxy();
 | 
|          DCHECK_NOT_NULL(var);
 | 
|          FunctionTableIndices* indices = LookupFunctionTable(var->var());
 | 
| -        current_function_builder_->EmitWithVarInt(kExprCallIndirect,
 | 
| -                                                  indices->signature_index);
 | 
| -        current_function_builder_->Emit(kExprI32Add);
 | 
| -        // TODO(bradnelson): variable size
 | 
| -        byte code[] = {WASM_I32V(indices->start_index)};
 | 
| -        current_function_builder_->EmitCode(code, sizeof(code));
 | 
|          RECURSE(Visit(p->key()));
 | 
| +        current_function_builder_->EmitI32Const(indices->start_index);
 | 
| +        current_function_builder_->Emit(kExprI32Add);
 | 
| +        VisitCallArgs(expr);
 | 
| +        current_function_builder_->Emit(kExprCallIndirect);
 | 
| +        current_function_builder_->EmitVarInt(expr->arguments()->length());
 | 
| +        current_function_builder_->EmitVarInt(indices->signature_index);
 | 
|          break;
 | 
|        }
 | 
|        default:
 | 
|          UNREACHABLE();
 | 
|      }
 | 
| -    VisitCallArgs(expr);
 | 
|    }
 | 
|  
 | 
|    void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
 | 
| @@ -1164,6 +1270,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
 | 
|  
 | 
|    void VisitUnaryOperation(UnaryOperation* expr) {
 | 
| +    RECURSE(Visit(expr->expression()));
 | 
|      switch (expr->op()) {
 | 
|        case Token::NOT: {
 | 
|          DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
 | 
| @@ -1173,7 +1280,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        default:
 | 
|          UNREACHABLE();
 | 
|      }
 | 
| -    RECURSE(Visit(expr->expression()));
 | 
|    }
 | 
|  
 | 
|    void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
 | 
| @@ -1319,6 +1425,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    void VisitBinaryOperation(BinaryOperation* expr) {
 | 
|      ConvertOperation convertOperation = MatchBinaryOperation(expr);
 | 
|      if (convertOperation == kToDouble) {
 | 
| +      RECURSE(Visit(expr->left()));
 | 
|        TypeIndex type = TypeIndexOf(expr->left());
 | 
|        if (type == kInt32 || type == kFixnum) {
 | 
|          current_function_builder_->Emit(kExprF64SConvertI32);
 | 
| @@ -1329,8 +1436,8 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        } else {
 | 
|          UNREACHABLE();
 | 
|        }
 | 
| -      RECURSE(Visit(expr->left()));
 | 
|      } else if (convertOperation == kToInt) {
 | 
| +      RECURSE(Visit(GetLeft(expr)));
 | 
|        TypeIndex type = TypeIndexOf(GetLeft(expr));
 | 
|        if (type == kFloat32) {
 | 
|          current_function_builder_->Emit(kExprI32SConvertF32);
 | 
| @@ -1339,10 +1446,20 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        } else {
 | 
|          UNREACHABLE();
 | 
|        }
 | 
| -      RECURSE(Visit(GetLeft(expr)));
 | 
|      } else if (convertOperation == kAsIs) {
 | 
|        RECURSE(Visit(GetLeft(expr)));
 | 
|      } else {
 | 
| +      if (expr->op() == Token::COMMA) {
 | 
| +        current_function_builder_->Emit(kExprBlock);
 | 
| +      }
 | 
| +
 | 
| +      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);
 | 
| @@ -1369,18 +1486,17 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|            break;
 | 
|          }
 | 
|          case Token::COMMA: {
 | 
| -          current_function_builder_->EmitWithVarInt(kExprBlock, 2);
 | 
|            break;
 | 
|          }
 | 
|          default:
 | 
|            UNREACHABLE();
 | 
|        }
 | 
| -      RECURSE(Visit(expr->left()));
 | 
| -      RECURSE(Visit(expr->right()));
 | 
|      }
 | 
|    }
 | 
|  
 | 
|    void VisitCompareOperation(CompareOperation* expr) {
 | 
| +    RECURSE(Visit(expr->left()));
 | 
| +    RECURSE(Visit(expr->right()));
 | 
|      switch (expr->op()) {
 | 
|        BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
 | 
|        BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
 | 
| @@ -1390,8 +1506,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|        default:
 | 
|          UNREACHABLE();
 | 
|      }
 | 
| -    RECURSE(Visit(expr->left()));
 | 
| -    RECURSE(Visit(expr->right()));
 | 
|    }
 | 
|  
 | 
|  #undef BINOP_CASE
 | 
| @@ -1553,9 +1667,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    ZoneHashMap local_variables_;
 | 
|    ZoneHashMap functions_;
 | 
|    ZoneHashMap global_variables_;
 | 
| -  bool in_function_;
 | 
| -  bool is_set_op_;
 | 
| -  bool marking_exported;
 | 
| +  AsmScope scope_;
 | 
|    WasmModuleBuilder* builder_;
 | 
|    WasmFunctionBuilder* current_function_builder_;
 | 
|    FunctionLiteral* literal_;
 | 
| @@ -1565,7 +1677,6 @@ class AsmWasmBuilderImpl : public AstVisitor {
 | 
|    AsmTyper* typer_;
 | 
|    TypeCache const& cache_;
 | 
|    ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
 | 
| -  int block_size_;
 | 
|    uint16_t init_function_index_;
 | 
|    uint32_t next_table_index_;
 | 
|    ZoneHashMap function_tables_;
 | 
| 
 |