Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE

This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.

FPIIM-449

Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/src/wasm/asm-wasm-builder.cc b/src/wasm/asm-wasm-builder.cc
index 30f8464..ee5427b 100644
--- a/src/wasm/asm-wasm-builder.cc
+++ b/src/wasm/asm-wasm-builder.cc
@@ -27,7 +27,8 @@
 
 class AsmWasmBuilderImpl : public AstVisitor {
  public:
-  AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal)
+  AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
+                     Handle<Object> foreign)
       : local_variables_(HashMap::PointersMatch,
                          ZoneHashMap::kDefaultHashMapCapacity,
                          ZoneAllocationPolicy(zone)),
@@ -44,17 +45,23 @@
         literal_(literal),
         isolate_(isolate),
         zone_(zone),
+        foreign_(foreign),
         cache_(TypeCache::Get()),
         breakable_blocks_(zone),
         block_size_(0),
-        init_function_index(0) {
+        init_function_index_(0),
+        next_table_index_(0),
+        function_tables_(HashMap::PointersMatch,
+                         ZoneHashMap::kDefaultHashMapCapacity,
+                         ZoneAllocationPolicy(zone)),
+        imported_function_table_(this) {
     InitializeAstVisitor(isolate);
   }
 
   void InitializeInitFunction() {
     unsigned char init[] = "__init__";
-    init_function_index = builder_->AddFunction();
-    current_function_builder_ = builder_->FunctionAt(init_function_index);
+    init_function_index_ = builder_->AddFunction();
+    current_function_builder_ = builder_->FunctionAt(init_function_index_);
     current_function_builder_->SetName(init, 8);
     current_function_builder_->ReturnType(kAstStmt);
     current_function_builder_->Exported(1);
@@ -70,7 +77,7 @@
 
   void VisitFunctionDeclaration(FunctionDeclaration* decl) {
     DCHECK(!in_function_);
-    DCHECK(current_function_builder_ == nullptr);
+    DCHECK_NULL(current_function_builder_);
     uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
     current_function_builder_ = builder_->FunctionAt(index);
     in_function_ = true;
@@ -103,11 +110,15 @@
         }
       }
     }
-    DCHECK(in_function_);
-    BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
-                         static_cast<byte>(stmt->statements()->length()));
-    RECURSE(VisitStatements(stmt->statements()));
-    DCHECK(block_size_ >= 0);
+    if (in_function_) {
+      BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
+                           false,
+                           static_cast<byte>(stmt->statements()->length()));
+      RECURSE(VisitStatements(stmt->statements()));
+      DCHECK(block_size_ >= 0);
+    } else {
+      RECURSE(VisitStatements(stmt->statements()));
+    }
   }
 
   class BlockVisitor {
@@ -162,7 +173,7 @@
 
   void VisitContinueStatement(ContinueStatement* stmt) {
     DCHECK(in_function_);
-    DCHECK(stmt->target() != NULL);
+    DCHECK_NOT_NULL(stmt->target());
     int i = static_cast<int>(breakable_blocks_.size()) - 1;
     int block_distance = 0;
     for (; i >= 0; i--) {
@@ -183,7 +194,7 @@
 
   void VisitBreakStatement(BreakStatement* stmt) {
     DCHECK(in_function_);
-    DCHECK(stmt->target() != NULL);
+    DCHECK_NOT_NULL(stmt->target());
     int i = static_cast<int>(breakable_blocks_.size()) - 1;
     int block_distance = 0;
     for (; i >= 0; i--) {
@@ -229,7 +240,7 @@
   void CompileCase(CaseClause* clause, uint16_t fall_through,
                    VariableProxy* tag) {
     Literal* label = clause->label()->AsLiteral();
-    DCHECK(label != nullptr);
+    DCHECK_NOT_NULL(label);
     block_size_++;
     current_function_builder_->Emit(kExprIf);
     current_function_builder_->Emit(kExprI32Ior);
@@ -247,7 +258,7 @@
 
   void VisitSwitchStatement(SwitchStatement* stmt) {
     VariableProxy* tag = stmt->tag()->AsVariableProxy();
-    DCHECK(tag != NULL);
+    DCHECK_NOT_NULL(tag);
     BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
                          0);
     uint16_t fall_through = current_function_builder_->AddLocal(kAstI32);
@@ -332,20 +343,20 @@
     Scope* scope = expr->scope();
     if (in_function_) {
       if (expr->bounds().lower->IsFunction()) {
-        Type::FunctionType* func_type = expr->bounds().lower->AsFunction();
+        FunctionType* func_type = expr->bounds().lower->AsFunction();
         LocalType return_type = TypeFrom(func_type->Result());
         current_function_builder_->ReturnType(return_type);
         for (int i = 0; i < expr->parameter_count(); i++) {
           LocalType type = TypeFrom(func_type->Parameter(i));
-          DCHECK(type != kAstStmt);
+          DCHECK_NE(kAstStmt, type);
           LookupOrInsertLocal(scope->parameter(i), type);
         }
       } else {
         UNREACHABLE();
       }
     }
-    RECURSE(VisitDeclarations(scope->declarations()));
     RECURSE(VisitStatements(expr->body()));
+    RECURSE(VisitDeclarations(scope->declarations()));
   }
 
   void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
@@ -363,34 +374,26 @@
   void VisitVariableProxy(VariableProxy* expr) {
     if (in_function_) {
       Variable* var = expr->var();
-      if (var->is_function()) {
-        DCHECK(!is_set_op_);
-        std::vector<uint8_t> index =
-            UnsignedLEB128From(LookupOrInsertFunction(var));
-        current_function_builder_->EmitCode(
-            &index[0], static_cast<uint32_t>(index.size()));
-      } else {
-        if (is_set_op_) {
-          if (var->IsContextSlot()) {
-            current_function_builder_->Emit(kExprStoreGlobal);
-          } else {
-            current_function_builder_->Emit(kExprSetLocal);
-          }
-          is_set_op_ = false;
-        } else {
-          if (var->IsContextSlot()) {
-            current_function_builder_->Emit(kExprLoadGlobal);
-          } else {
-            current_function_builder_->Emit(kExprGetLocal);
-          }
-        }
-        LocalType var_type = TypeOf(expr);
-        DCHECK(var_type != kAstStmt);
+      if (is_set_op_) {
         if (var->IsContextSlot()) {
-          AddLeb128(LookupOrInsertGlobal(var, var_type), false);
+          current_function_builder_->Emit(kExprStoreGlobal);
         } else {
-          AddLeb128(LookupOrInsertLocal(var, var_type), true);
+          current_function_builder_->Emit(kExprSetLocal);
         }
+        is_set_op_ = false;
+      } else {
+        if (var->IsContextSlot()) {
+          current_function_builder_->Emit(kExprLoadGlobal);
+        } else {
+          current_function_builder_->Emit(kExprGetLocal);
+        }
+      }
+      LocalType var_type = TypeOf(expr);
+      DCHECK_NE(kAstStmt, var_type);
+      if (var->IsContextSlot()) {
+        AddLeb128(LookupOrInsertGlobal(var, var_type), false);
+      } else {
+        AddLeb128(LookupOrInsertLocal(var, var_type), true);
       }
     }
   }
@@ -433,10 +436,10 @@
       ObjectLiteralProperty* prop = props->at(i);
       DCHECK(marking_exported);
       VariableProxy* expr = prop->value()->AsVariableProxy();
-      DCHECK(expr != nullptr);
+      DCHECK_NOT_NULL(expr);
       Variable* var = expr->var();
       Literal* name = prop->key()->AsLiteral();
-      DCHECK(name != nullptr);
+      DCHECK_NOT_NULL(name);
       DCHECK(name->IsPropertyName());
       const AstRawString* raw_name = name->AsRawPropertyName();
       if (var->is_function()) {
@@ -451,7 +454,7 @@
   void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
 
   void LoadInitFunction() {
-    current_function_builder_ = builder_->FunctionAt(init_function_index);
+    current_function_builder_ = builder_->FunctionAt(init_function_index_);
     in_function_ = true;
   }
 
@@ -460,11 +463,155 @@
     current_function_builder_ = nullptr;
   }
 
+  void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
+    FunctionType* func_type =
+        funcs->bounds().lower->AsArray()->Element()->AsFunction();
+    LocalType return_type = TypeFrom(func_type->Result());
+    FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
+                             func_type->Arity());
+    if (return_type != kAstStmt) {
+      sig.AddReturn(static_cast<LocalType>(return_type));
+    }
+    for (int i = 0; i < func_type->Arity(); i++) {
+      sig.AddParam(TypeFrom(func_type->Parameter(i)));
+    }
+    uint16_t signature_index = builder_->AddSignature(sig.Build());
+    InsertFunctionTable(table->var(), next_table_index_, signature_index);
+    next_table_index_ += funcs->values()->length();
+    for (int i = 0; i < funcs->values()->length(); i++) {
+      VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
+      DCHECK_NOT_NULL(func);
+      builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
+    }
+  }
+
+  struct FunctionTableIndices : public ZoneObject {
+    uint32_t start_index;
+    uint16_t signature_index;
+  };
+
+  void InsertFunctionTable(Variable* v, uint32_t start_index,
+                           uint16_t signature_index) {
+    FunctionTableIndices* container = new (zone()) FunctionTableIndices();
+    container->start_index = start_index;
+    container->signature_index = signature_index;
+    ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
+        v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
+    entry->value = container;
+  }
+
+  FunctionTableIndices* LookupFunctionTable(Variable* v) {
+    ZoneHashMap::Entry* entry =
+        function_tables_.Lookup(v, ComputePointerHash(v));
+    DCHECK_NOT_NULL(entry);
+    return reinterpret_cast<FunctionTableIndices*>(entry->value);
+  }
+
+  class ImportedFunctionTable {
+   private:
+    class ImportedFunctionIndices : public ZoneObject {
+     public:
+      const unsigned char* name_;
+      int name_length_;
+      WasmModuleBuilder::SignatureMap signature_to_index_;
+
+      ImportedFunctionIndices(const unsigned char* name, int name_length,
+                              Zone* zone)
+          : name_(name), name_length_(name_length), signature_to_index_(zone) {}
+    };
+    ZoneHashMap table_;
+    AsmWasmBuilderImpl* builder_;
+
+   public:
+    explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
+        : table_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
+                 ZoneAllocationPolicy(builder->zone())),
+          builder_(builder) {}
+
+    void AddImport(Variable* v, const unsigned char* name, int name_length) {
+      ImportedFunctionIndices* indices = new (builder_->zone())
+          ImportedFunctionIndices(name, name_length, builder_->zone());
+      ZoneHashMap::Entry* entry = table_.LookupOrInsert(
+          v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
+      entry->value = indices;
+    }
+
+    uint16_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
+      ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
+      DCHECK_NOT_NULL(entry);
+      ImportedFunctionIndices* indices =
+          reinterpret_cast<ImportedFunctionIndices*>(entry->value);
+      WasmModuleBuilder::SignatureMap::iterator pos =
+          indices->signature_to_index_.find(sig);
+      if (pos != indices->signature_to_index_.end()) {
+        return pos->second;
+      } else {
+        uint16_t index = builder_->builder_->AddFunction();
+        indices->signature_to_index_[sig] = index;
+        WasmFunctionBuilder* function = builder_->builder_->FunctionAt(index);
+        function->External(1);
+        function->SetName(indices->name_, indices->name_length_);
+        if (sig->return_count() > 0) {
+          function->ReturnType(sig->GetReturn());
+        }
+        for (size_t i = 0; i < sig->parameter_count(); i++) {
+          function->AddParam(sig->GetParam(i));
+        }
+        return index;
+      }
+    }
+  };
+
   void VisitAssignment(Assignment* expr) {
     bool in_init = false;
     if (!in_function_) {
+      BinaryOperation* binop = expr->value()->AsBinaryOperation();
+      if (binop != nullptr) {
+        Property* prop = binop->left()->AsProperty();
+        DCHECK_NOT_NULL(prop);
+        LoadInitFunction();
+        is_set_op_ = true;
+        RECURSE(Visit(expr->target()));
+        DCHECK(!is_set_op_);
+        if (binop->op() == Token::MUL) {
+          DCHECK(binop->right()->IsLiteral());
+          DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
+          DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
+          VisitForeignVariable(true, prop);
+        } else if (binop->op() == Token::BIT_OR) {
+          DCHECK(binop->right()->IsLiteral());
+          DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
+          DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
+          VisitForeignVariable(false, prop);
+        } else {
+          UNREACHABLE();
+        }
+        UnLoadInitFunction();
+        return;
+      }
       // TODO(bradnelson): Get rid of this.
       if (TypeOf(expr->value()) == kAstStmt) {
+        Property* prop = expr->value()->AsProperty();
+        if (prop != nullptr) {
+          VariableProxy* vp = prop->obj()->AsVariableProxy();
+          if (vp != nullptr && vp->var()->IsParameter() &&
+              vp->var()->index() == 1) {
+            VariableProxy* target = expr->target()->AsVariableProxy();
+            if (target->bounds().lower->Is(Type::Function())) {
+              const AstRawString* name =
+                  prop->key()->AsLiteral()->AsRawPropertyName();
+              imported_function_table_.AddImport(
+                  target->var(), name->raw_data(), name->length());
+            }
+          }
+        }
+        ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
+        if (funcs != nullptr &&
+            funcs->bounds().lower->AsArray()->Element()->IsFunction()) {
+          VariableProxy* target = expr->target()->AsVariableProxy();
+          DCHECK_NOT_NULL(target);
+          AddFunctionTable(target, funcs);
+        }
         return;
       }
       in_init = true;
@@ -493,10 +640,59 @@
 
   void VisitThrow(Throw* expr) { UNREACHABLE(); }
 
+  void VisitForeignVariable(bool is_float, Property* expr) {
+    DCHECK(expr->obj()->AsVariableProxy());
+    DCHECK(VariableLocation::PARAMETER ==
+           expr->obj()->AsVariableProxy()->var()->location());
+    DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
+    Literal* key_literal = expr->key()->AsLiteral();
+    DCHECK_NOT_NULL(key_literal);
+    if (!key_literal->value().is_null() && !foreign_.is_null() &&
+        foreign_->IsObject()) {
+      Handle<Name> name =
+          i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
+      MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name);
+      if (!maybe_value.is_null()) {
+        Handle<Object> value = maybe_value.ToHandleChecked();
+        if (is_float) {
+          MaybeHandle<Object> maybe_nvalue = i::Object::ToNumber(value);
+          if (!maybe_nvalue.is_null()) {
+            Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
+            if (nvalue->IsNumber()) {
+              double val = nvalue->Number();
+              byte code[] = {WASM_F64(val)};
+              current_function_builder_->EmitCode(code, sizeof(code));
+              return;
+            }
+          }
+        } else {
+          MaybeHandle<Object> maybe_nvalue =
+              i::Object::ToInt32(isolate_, value);
+          if (!maybe_nvalue.is_null()) {
+            Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
+            if (nvalue->IsNumber()) {
+              int32_t val = static_cast<int32_t>(nvalue->Number());
+              byte code[] = {WASM_I32(val)};
+              current_function_builder_->EmitCode(code, sizeof(code));
+              return;
+            }
+          }
+        }
+      }
+    }
+    if (is_float) {
+      byte code[] = {WASM_F64(std::numeric_limits<double>::quiet_NaN())};
+      current_function_builder_->EmitCode(code, sizeof(code));
+    } else {
+      byte code[] = {WASM_I32(0)};
+      current_function_builder_->EmitCode(code, sizeof(code));
+    }
+  }
+
   void VisitProperty(Property* expr) {
     Expression* obj = expr->obj();
-    DCHECK(obj->bounds().lower == obj->bounds().upper);
-    TypeImpl<ZoneTypeConfig>* type = obj->bounds().lower;
+    DCHECK_EQ(obj->bounds().lower, obj->bounds().upper);
+    Type* type = obj->bounds().lower;
     MachineType mtype;
     int size;
     if (type->Is(cache_.kUint8Array)) {
@@ -533,29 +729,38 @@
         WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_),
         WasmOpcodes::LoadStoreAccessOf(false));
     is_set_op_ = false;
-    Literal* value = expr->key()->AsLiteral();
-    if (value) {
-      DCHECK(value->raw_value()->IsNumber());
-      DCHECK(kAstI32 == TypeOf(value));
-      int val = static_cast<int>(value->raw_value()->AsNumber());
-      byte code[] = {WASM_I32(val * size)};
-      current_function_builder_->EmitCode(code, sizeof(code));
+    if (size == 1) {
+      // Allow more general expression in byte arrays than the spec
+      // strictly permits.
+      // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
+      // places that strictly should be HEAP8[HEAP32[..]>>0].
+      RECURSE(Visit(expr->key()));
       return;
-    }
-    BinaryOperation* binop = expr->key()->AsBinaryOperation();
-    if (binop) {
-      DCHECK(Token::SAR == binop->op());
-      DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
-      DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
-      DCHECK(size ==
-             1 << static_cast<int>(
-                 binop->right()->AsLiteral()->raw_value()->AsNumber()));
-      // Mask bottom bits to match asm.js behavior.
-      current_function_builder_->Emit(kExprI32And);
-      byte code[] = {WASM_I8(~(size - 1))};
-      current_function_builder_->EmitCode(code, sizeof(code));
-      RECURSE(Visit(binop->left()));
-      return;
+    } else {
+      Literal* value = expr->key()->AsLiteral();
+      if (value) {
+        DCHECK(value->raw_value()->IsNumber());
+        DCHECK_EQ(kAstI32, TypeOf(value));
+        int val = static_cast<int>(value->raw_value()->AsNumber());
+        byte code[] = {WASM_I32(val * size)};
+        current_function_builder_->EmitCode(code, sizeof(code));
+        return;
+      }
+      BinaryOperation* binop = expr->key()->AsBinaryOperation();
+      if (binop) {
+        DCHECK_EQ(Token::SAR, binop->op());
+        DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
+        DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
+        DCHECK_EQ(size,
+                  1 << static_cast<int>(
+                      binop->right()->AsLiteral()->raw_value()->AsNumber()));
+        // Mask bottom bits to match asm.js behavior.
+        current_function_builder_->Emit(kExprI32And);
+        byte code[] = {WASM_I8(~(size - 1))};
+        current_function_builder_->EmitCode(code, sizeof(code));
+        RECURSE(Visit(binop->left()));
+        return;
+      }
     }
     UNREACHABLE();
   }
@@ -565,18 +770,54 @@
     switch (call_type) {
       case Call::OTHER_CALL: {
         DCHECK(in_function_);
-        current_function_builder_->Emit(kExprCallFunction);
-        RECURSE(Visit(expr->expression()));
-        ZoneList<Expression*>* args = expr->arguments();
-        for (int i = 0; i < args->length(); ++i) {
-          Expression* arg = args->at(i);
-          RECURSE(Visit(arg));
+        uint16_t index;
+        VariableProxy* vp = expr->expression()->AsVariableProxy();
+        if (vp != nullptr &&
+            Type::Any()->Is(vp->bounds().lower->AsFunction()->Result())) {
+          LocalType return_type = TypeOf(expr);
+          ZoneList<Expression*>* args = expr->arguments();
+          FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
+                                   args->length());
+          if (return_type != kAstStmt) {
+            sig.AddReturn(return_type);
+          }
+          for (int i = 0; i < args->length(); i++) {
+            sig.AddParam(TypeOf(args->at(i)));
+          }
+          index =
+              imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
+        } else {
+          index = LookupOrInsertFunction(vp->var());
         }
+        current_function_builder_->Emit(kExprCallFunction);
+        std::vector<uint8_t> index_arr = UnsignedLEB128From(index);
+        current_function_builder_->EmitCode(
+            &index_arr[0], static_cast<uint32_t>(index_arr.size()));
+        break;
+      }
+      case Call::KEYED_PROPERTY_CALL: {
+        DCHECK(in_function_);
+        Property* p = expr->expression()->AsProperty();
+        DCHECK_NOT_NULL(p);
+        VariableProxy* var = p->obj()->AsVariableProxy();
+        DCHECK_NOT_NULL(var);
+        FunctionTableIndices* indices = LookupFunctionTable(var->var());
+        current_function_builder_->EmitWithU8(kExprCallIndirect,
+                                              indices->signature_index);
+        current_function_builder_->Emit(kExprI32Add);
+        byte code[] = {WASM_I32(indices->start_index)};
+        current_function_builder_->EmitCode(code, sizeof(code));
+        RECURSE(Visit(p->key()));
         break;
       }
       default:
         UNREACHABLE();
     }
+    ZoneList<Expression*>* args = expr->arguments();
+    for (int i = 0; i < args->length(); ++i) {
+      Expression* arg = args->at(i);
+      RECURSE(Visit(arg));
+    }
   }
 
   void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
@@ -586,7 +827,7 @@
   void VisitUnaryOperation(UnaryOperation* expr) {
     switch (expr->op()) {
       case Token::NOT: {
-        DCHECK(TypeOf(expr->expression()) == kAstI32);
+        DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
         current_function_builder_->Emit(kExprBoolNot);
         break;
       }
@@ -600,7 +841,7 @@
 
   bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
                                int32_t val) {
-    DCHECK(expr->right() != nullptr);
+    DCHECK_NOT_NULL(expr->right());
     if (expr->op() == op && expr->right()->IsLiteral() &&
         TypeOf(expr) == kAstI32) {
       Literal* right = expr->right()->AsLiteral();
@@ -614,7 +855,7 @@
 
   bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
                                   double val) {
-    DCHECK(expr->right() != nullptr);
+    DCHECK_NOT_NULL(expr->right());
     if (expr->op() == op && expr->right()->IsLiteral() &&
         TypeOf(expr) == kAstF64) {
       Literal* right = expr->right()->AsLiteral();
@@ -629,8 +870,9 @@
   enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
 
   ConvertOperation MatchOr(BinaryOperation* expr) {
-    if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0)) {
-      return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
+    if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
+        (TypeOf(expr->left()) == kAstI32)) {
+      return kAsIs;
     } else {
       return kNone;
     }
@@ -647,12 +889,12 @@
 
   ConvertOperation MatchXor(BinaryOperation* expr) {
     if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
-      DCHECK(TypeOf(expr->left()) == kAstI32);
-      DCHECK(TypeOf(expr->right()) == kAstI32);
+      DCHECK_EQ(kAstI32, TypeOf(expr->left()));
+      DCHECK_EQ(kAstI32, TypeOf(expr->right()));
       BinaryOperation* op = expr->left()->AsBinaryOperation();
       if (op != nullptr) {
         if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
-          DCHECK(TypeOf(op->right()) == kAstI32);
+          DCHECK_EQ(kAstI32, TypeOf(op->right()));
           if (TypeOf(op->left()) != kAstI32) {
             return kToInt;
           } else {
@@ -666,7 +908,7 @@
 
   ConvertOperation MatchMul(BinaryOperation* expr) {
     if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
-      DCHECK(TypeOf(expr->right()) == kAstF64);
+      DCHECK_EQ(kAstF64, TypeOf(expr->right()));
       if (TypeOf(expr->left()) != kAstF64) {
         return kToDouble;
       } else {
@@ -768,6 +1010,7 @@
         BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
         BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
         BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
+        BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
         BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
         BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
         BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
@@ -786,6 +1029,10 @@
           }
           break;
         }
+        case Token::COMMA: {
+          current_function_builder_->EmitWithU8(kExprBlock, 2);
+          break;
+        }
         default:
           UNREACHABLE();
       }
@@ -879,8 +1126,8 @@
   }
 
   TypeIndex TypeIndexOf(Expression* expr) {
-    DCHECK(expr->bounds().lower == expr->bounds().upper);
-    TypeImpl<ZoneTypeConfig>* type = expr->bounds().lower;
+    DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
+    Type* type = expr->bounds().lower;
     if (type->Is(cache_.kAsmFixnum)) {
       return kFixnum;
     } else if (type->Is(cache_.kAsmSigned)) {
@@ -929,17 +1176,14 @@
 
   void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
 
-  void VisitRewritableAssignmentExpression(
-      RewritableAssignmentExpression* expr) {
-    UNREACHABLE();
-  }
+  void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
 
   struct IndexContainer : public ZoneObject {
     uint16_t index;
   };
 
   uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
-    DCHECK(current_function_builder_ != nullptr);
+    DCHECK_NOT_NULL(current_function_builder_);
     ZoneHashMap::Entry* entry =
         local_variables_.Lookup(v, ComputePointerHash(v));
     if (entry == nullptr) {
@@ -974,7 +1218,7 @@
   }
 
   uint16_t LookupOrInsertFunction(Variable* v) {
-    DCHECK(builder_ != nullptr);
+    DCHECK_NOT_NULL(builder_);
     ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
     if (entry == nullptr) {
       uint16_t index = builder_->AddFunction();
@@ -988,11 +1232,11 @@
   }
 
   LocalType TypeOf(Expression* expr) {
-    DCHECK(expr->bounds().lower == expr->bounds().upper);
+    DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
     return TypeFrom(expr->bounds().lower);
   }
 
-  LocalType TypeFrom(TypeImpl<ZoneTypeConfig>* type) {
+  LocalType TypeFrom(Type* type) {
     if (type->Is(cache_.kAsmInt)) {
       return kAstI32;
     } else if (type->Is(cache_.kAsmFloat)) {
@@ -1017,10 +1261,14 @@
   FunctionLiteral* literal_;
   Isolate* isolate_;
   Zone* zone_;
+  Handle<Object> foreign_;
   TypeCache const& cache_;
   ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
   int block_size_;
-  uint16_t init_function_index;
+  uint16_t init_function_index_;
+  uint32_t next_table_index_;
+  ZoneHashMap function_tables_;
+  ImportedFunctionTable imported_function_table_;
 
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
 
@@ -1029,13 +1277,13 @@
 };
 
 AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
-                               FunctionLiteral* literal)
-    : isolate_(isolate), zone_(zone), literal_(literal) {}
+                               FunctionLiteral* literal, Handle<Object> foreign)
+    : isolate_(isolate), zone_(zone), literal_(literal), foreign_(foreign) {}
 
 // TODO(aseemgarg): probably should take zone (to write wasm to) as input so
 // that zone in constructor may be thrown away once wasm module is written.
 WasmModuleIndex* AsmWasmBuilder::Run() {
-  AsmWasmBuilderImpl impl(isolate_, zone_, literal_);
+  AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_);
   impl.Compile();
   WasmModuleWriter* writer = impl.builder_->Build(zone_);
   return writer->WriteTo(zone_);