Loads and stores to global vars are now made via property cell shortcuts installed...
authorishell <ishell@chromium.org>
Mon, 13 Jul 2015 09:18:44 +0000 (02:18 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 13 Jul 2015 09:18:57 +0000 (09:18 +0000)
This CL also adds hydrogen stubs for global loads and global stores, full-codegen and TurboFan now uses this machinery.

Review URL: https://codereview.chromium.org/1224793002

Cr-Commit-Position: refs/heads/master@{#29592}

40 files changed:
src/arm/full-codegen-arm.cc
src/arm/interface-descriptors-arm.cc
src/arm64/full-codegen-arm64.cc
src/arm64/interface-descriptors-arm64.cc
src/ast.cc
src/ast.h
src/code-factory.cc
src/code-factory.h
src/code-stubs-hydrogen.cc
src/code-stubs.cc
src/code-stubs.h
src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/js-generic-lowering.cc
src/compiler/js-operator.cc
src/compiler/js-operator.h
src/compiler/js-typed-lowering.cc
src/flag-definitions.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/full-codegen-ia32.cc
src/ia32/interface-descriptors-ia32.cc
src/interface-descriptors.cc
src/interface-descriptors.h
src/mips/full-codegen-mips.cc
src/mips/interface-descriptors-mips.cc
src/mips64/full-codegen-mips64.cc
src/mips64/interface-descriptors-mips64.cc
src/ppc/full-codegen-ppc.cc
src/ppc/interface-descriptors-ppc.cc
src/runtime/runtime-object.cc
src/runtime/runtime.h
src/scopes.cc
src/x64/full-codegen-x64.cc
src/x64/interface-descriptors-x64.cc
src/x87/full-codegen-x87.cc
src/x87/interface-descriptors-x87.cc
test/unittests/compiler/js-type-feedback-unittest.cc
test/unittests/compiler/js-typed-lowering-unittest.cc

index 3dea3bc18b16b07b790135ed02cd314faf4512e7..5c4533aa139a987729f9aa51e864fdc66927e19d 100644 (file)
@@ -1492,13 +1492,30 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
-  __ mov(LoadDescriptor::SlotRegister(),
-         Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+           Operand(Smi::FromInt(depth)));
+    __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+           Operand(Smi::FromInt(slot_index)));
+    __ mov(LoadGlobalViaContextDescriptor::NameRegister(),
+           Operand(var->name()));
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+    __ mov(LoadDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2753,13 +2770,30 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ mov(StoreDescriptor::NameRegister(), Operand(var->name()));
     __ ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+           Operand(Smi::FromInt(depth)));
+    __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+           Operand(Smi::FromInt(slot_index)));
+    __ mov(StoreGlobalViaContextDescriptor::NameRegister(),
+           Operand(var->name()));
+    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(r0));
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index 3dd5fab0e37ceb6374b88fa748c419be3ec38565..f65b6d272d7679e2b4114b0a835262dfa10e98a8 100644 (file)
@@ -36,6 +36,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return r3; }
 const Register StoreTransitionDescriptor::MapRegister() { return r3; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return r1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return r2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return r3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return r1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return r2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return r3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return r0; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r3; }
 
 
index 9896771b5813ea3a5b57749c8db9cba5ca714074..9027f51b7128b1e9b4d1a0d4014198317a11b0f6 100644 (file)
@@ -1472,13 +1472,30 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
-  __ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
-  __ Mov(LoadDescriptor::SlotRegister(),
-         SmiFromSlot(proxy->VariableFeedbackSlot()));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ Mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+           Operand(Smi::FromInt(depth)));
+    __ Mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+           Operand(Smi::FromInt(slot_index)));
+    __ Mov(LoadGlobalViaContextDescriptor::NameRegister(),
+           Operand(var->name()));
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
+    __ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+    __ Mov(LoadDescriptor::SlotRegister(),
+           SmiFromSlot(proxy->VariableFeedbackSlot()));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2439,13 +2456,30 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
   ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ Mov(StoreDescriptor::NameRegister(), Operand(var->name()));
     __ Ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ Mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+           Operand(Smi::FromInt(depth)));
+    __ Mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+           Operand(Smi::FromInt(slot_index)));
+    __ Mov(StoreGlobalViaContextDescriptor::NameRegister(),
+           Operand(var->name()));
+    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(x0));
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index 8412c46ea0f38eab46aaa7c683c1d4e438705f0c..d6aa2573d05c12482f3f16a6aea6aaf4af3d60c0 100644 (file)
@@ -36,6 +36,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return x3; }
 const Register StoreTransitionDescriptor::MapRegister() { return x3; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return x1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return x2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return x3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return x1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return x2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return x3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return x0; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return x3; }
 
 
index 8ce5e7e29c9a5c86631867ac91d26175061b0038..f7eab6ec710dd438fbe3d9095e90f5e00e086d85 100644 (file)
@@ -95,7 +95,7 @@ void VariableProxy::BindTo(Variable* var) {
 void VariableProxy::SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
                                            ICSlotCache* cache) {
   variable_feedback_slot_ = slot;
-  if (var()->IsUnallocatedOrGlobalSlot()) {
+  if (var()->IsUnallocated()) {
     cache->Add(VariableICSlotPair(var(), slot));
   }
 }
@@ -106,7 +106,7 @@ FeedbackVectorRequirements VariableProxy::ComputeFeedbackRequirements(
   if (UsesVariableFeedbackSlot()) {
     // VariableProxies that point to the same Variable within a function can
     // make their loads from the same IC slot.
-    if (var()->IsUnallocatedOrGlobalSlot()) {
+    if (var()->IsUnallocated()) {
       for (int i = 0; i < cache->length(); i++) {
         VariableICSlotPair& pair = cache->at(i);
         if (pair.variable() == var()) {
@@ -127,7 +127,7 @@ static int GetStoreICSlots(Expression* expr) {
     Property* property = expr->AsProperty();
     LhsKind assign_type = Property::GetAssignType(property);
     if ((assign_type == VARIABLE &&
-         expr->AsVariableProxy()->var()->IsUnallocatedOrGlobalSlot()) ||
+         expr->AsVariableProxy()->var()->IsUnallocated()) ||
         assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
       ic_slots++;
     }
@@ -289,8 +289,7 @@ FeedbackVectorRequirements ClassLiteral::ComputeFeedbackRequirements(
     if (FunctionLiteral::NeedsHomeObject(value)) ic_slots++;
   }
 
-  if (scope() != NULL &&
-      class_variable_proxy()->var()->IsUnallocatedOrGlobalSlot()) {
+  if (scope() != NULL && class_variable_proxy()->var()->IsUnallocated()) {
     ic_slots++;
   }
 
index a6a06269cb3385a333f08a8b7a52a5b3903e2af0..2e2f4ca1e1512f0f90e8e9f236aa7807caec4c7b 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1667,7 +1667,7 @@ class VariableProxy final : public Expression {
   void BindTo(Variable* var);
 
   bool UsesVariableFeedbackSlot() const {
-    return var()->IsUnallocatedOrGlobalSlot() || var()->IsLookupSlot();
+    return var()->IsUnallocated() || var()->IsLookupSlot();
   }
 
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
index bdceb572a123766faae53a79cf694626d964b9be..bcd579564547d6a13fed95e21c69534ff0039113 100644 (file)
@@ -138,6 +138,21 @@ Callable CodeFactory::BinaryOpIC(Isolate* isolate, Token::Value op,
 }
 
 
+// static
+Callable CodeFactory::LoadGlobalViaContext(Isolate* isolate, int depth) {
+  LoadGlobalViaContextStub stub(isolate, depth);
+  return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
+// static
+Callable CodeFactory::StoreGlobalViaContext(Isolate* isolate, int depth,
+                                            LanguageMode language_mode) {
+  StoreGlobalViaContextStub stub(isolate, depth, language_mode);
+  return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
 // static
 Callable CodeFactory::Instanceof(Isolate* isolate,
                                  InstanceofStub::Flags flags) {
index 947770db42f8db302a474c55fb6cc2ed19afaa88..4baf6f256b90ecc6a3d5d0db5df7d862d248b1da 100644 (file)
@@ -61,6 +61,10 @@ class CodeFactory final {
 
   // Code stubs. Add methods here as needed to reduce dependency on
   // code-stubs.h.
+  static Callable LoadGlobalViaContext(Isolate* isolate, int depth);
+  static Callable StoreGlobalViaContext(Isolate* isolate, int depth,
+                                        LanguageMode language_mode);
+
   static Callable Instanceof(Isolate* isolate, InstanceofStub::Flags flags);
 
   static Callable ToBoolean(
index d1cabde1bd4cec2fed8110a951c7578361d07dd7..154811c55e441bf349b90a33ea148749095d8873 100644 (file)
@@ -1605,7 +1605,221 @@ Handle<Code> StoreGlobalStub::GenerateCode() {
 }
 
 
-template<>
+template <>
+HValue* CodeStubGraphBuilder<LoadGlobalViaContextStub>::BuildCodeStub() {
+  LoadGlobalViaContextStub* stub = casted_stub();
+  int depth_value = stub->depth();
+  HValue* depth = GetParameter(0);
+  HValue* slot_index = GetParameter(1);
+  HValue* name = GetParameter(2);
+
+  // Choose between dynamic or static context script fetching versions.
+  depth = depth_value < LoadGlobalViaContextStub::kDynamicDepth
+              ? nullptr
+              : AddUncasted<HForceRepresentation>(depth, Representation::Smi());
+  slot_index =
+      AddUncasted<HForceRepresentation>(slot_index, Representation::Smi());
+
+  HValue* script_context = BuildGetParentContext(depth, depth_value);
+  HValue* cell =
+      Add<HLoadKeyed>(script_context, slot_index, nullptr, FAST_ELEMENTS);
+
+  HValue* value = Add<HLoadNamedField>(cell, nullptr,
+                                       HObjectAccess::ForPropertyCellValue());
+
+  IfBuilder builder(this);
+  HValue* hole_value = graph()->GetConstantHole();
+  builder.IfNot<HCompareObjectEqAndBranch, HValue*>(value, hole_value);
+  builder.Then();
+  { Push(value); }
+  builder.Else();
+  {
+    Add<HPushArguments>(script_context, slot_index, name);
+    Push(Add<HCallRuntime>(
+        isolate()->factory()->empty_string(),
+        Runtime::FunctionForId(Runtime::kLoadGlobalViaContext), 3));
+  }
+  builder.End();
+  return Pop();
+}
+
+
+Handle<Code> LoadGlobalViaContextStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
+HValue* CodeStubGraphBuilder<StoreGlobalViaContextStub>::BuildCodeStub() {
+  StoreGlobalViaContextStub* stub = casted_stub();
+  int depth_value = stub->depth();
+  HValue* depth = GetParameter(0);
+  HValue* slot_index = GetParameter(1);
+  HValue* name = GetParameter(2);
+  HValue* value = GetParameter(3);
+
+  // Choose between dynamic or static context script fetching versions.
+  depth = depth_value < StoreGlobalViaContextStub::kDynamicDepth
+              ? nullptr
+              : AddUncasted<HForceRepresentation>(depth, Representation::Smi());
+  slot_index =
+      AddUncasted<HForceRepresentation>(slot_index, Representation::Smi());
+
+  HValue* script_context = BuildGetParentContext(depth, depth_value);
+  HValue* cell =
+      Add<HLoadKeyed>(script_context, slot_index, nullptr, FAST_ELEMENTS);
+
+  // Fast case that requires storing to cell.
+  HIfContinuation if_fast_store_continuation(graph()->CreateBasicBlock(),
+                                             graph()->CreateBasicBlock());
+
+  // Fast case that does not require storing to cell.
+  HIfContinuation if_fast_no_store_continuation(graph()->CreateBasicBlock(),
+                                                graph()->CreateBasicBlock());
+
+  // This stub does the same as StoreGlobalStub but in a dynamic manner.
+
+  HValue* cell_contents = Add<HLoadNamedField>(
+      cell, nullptr, HObjectAccess::ForPropertyCellValue());
+
+  IfBuilder if_hole(this);
+  HValue* hole_value = graph()->GetConstantHole();
+  if_hole.IfNot<HCompareObjectEqAndBranch, HValue*>(cell_contents, hole_value);
+  if_hole.Then();
+  {
+    HValue* details = Add<HLoadNamedField>(
+        cell, nullptr, HObjectAccess::ForPropertyCellDetails());
+    HValue* cell_type =
+        BuildDecodeField<PropertyDetails::PropertyCellTypeField>(details);
+
+    // The code below relies on this.
+    STATIC_ASSERT(PropertyCellType::kUndefined < PropertyCellType::kConstant);
+    STATIC_ASSERT(PropertyCellType::kConstant <
+                  PropertyCellType::kConstantType);
+    STATIC_ASSERT(PropertyCellType::kConstant < PropertyCellType::kMutable);
+
+    // Handle all cell type cases.
+    IfBuilder if_not_const(this);
+
+    int cell_type_constant = static_cast<int>(PropertyCellType::kConstant);
+    if_not_const.If<HCompareNumericAndBranch, HValue*>(
+        cell_type, Add<HConstant>(cell_type_constant), Token::GT);
+    if_not_const.Then();
+    {
+      // kConstantType or kMutable.
+      IfBuilder if_const_type(this);
+      int cell_type_constant_type =
+          static_cast<int>(PropertyCellType::kConstantType);
+      if_const_type.If<HCompareNumericAndBranch, HValue*>(
+          cell_type, Add<HConstant>(cell_type_constant_type), Token::EQ);
+      if_const_type.Then();
+      {
+        // Check that either both value and cell_contents are smi or
+        // both have the same map.
+        IfBuilder if_cell_is_smi(this);
+        if_cell_is_smi.If<HIsSmiAndBranch>(cell_contents);
+        if_cell_is_smi.Then();
+        {
+          IfBuilder if_value_is_smi(this);
+          if_value_is_smi.If<HIsSmiAndBranch>(value);
+          if_value_is_smi.Then();
+          {
+            // Both cell_contents and value are smis, do store.
+          }
+          if_value_is_smi.Else();  // Slow case.
+          if_value_is_smi.JoinContinuation(&if_fast_store_continuation);
+        }
+        if_cell_is_smi.Else();
+        {
+          IfBuilder if_value_is_heap_object(this);
+          if_value_is_heap_object.IfNot<HIsSmiAndBranch>(value);
+          if_value_is_heap_object.Then();
+          {
+            // Both cell_contents and value are heap objects, do store.
+            HValue* expected_map = Add<HLoadNamedField>(
+                cell_contents, nullptr, HObjectAccess::ForMap());
+            HValue* map =
+                Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap());
+            IfBuilder map_check(this);
+            map_check.If<HCompareObjectEqAndBranch>(expected_map, map);
+            map_check.Then();
+            map_check.Else();  // Slow case.
+            map_check.JoinContinuation(&if_fast_store_continuation);
+
+            // The accessor case is handled by the map check above, since
+            // the value must not have a AccessorPair map.
+          }
+          if_value_is_heap_object.Else();  // Slow case.
+          if_value_is_heap_object.JoinContinuation(&if_fast_store_continuation);
+        }
+        if_cell_is_smi.EndUnreachable();
+      }
+      if_const_type.Else();
+      {
+        // Check that the property kind is kData.
+        HValue* kind = BuildDecodeField<PropertyDetails::KindField>(details);
+        HValue* data_kind_value = Add<HConstant>(kData);
+
+        IfBuilder builder(this);
+        builder.If<HCompareNumericAndBranch, HValue*>(kind, data_kind_value,
+                                                      Token::EQ);
+        builder.Then();
+        builder.Else();  // Slow case.
+        builder.JoinContinuation(&if_fast_store_continuation);
+      }
+      if_const_type.EndUnreachable();
+    }
+    if_not_const.Else();
+    {
+      // kUndefined or kConstant, just check that the value matches.
+      IfBuilder builder(this);
+      builder.If<HCompareObjectEqAndBranch>(cell_contents, value);
+      builder.Then();
+      builder.Else();  // Slow case.
+      builder.JoinContinuation(&if_fast_no_store_continuation);
+    }
+    if_not_const.EndUnreachable();
+  }
+  if_hole.Else();  // Slow case.
+  if_hole.JoinContinuation(&if_fast_store_continuation);
+
+  // Do store for fast case.
+  IfBuilder if_fast_store(this, &if_fast_store_continuation);
+  if_fast_store.Then();
+  {
+    // All checks are done, store the value to the cell.
+    Add<HStoreNamedField>(cell, HObjectAccess::ForPropertyCellValue(), value);
+  }
+  if_fast_store.Else();
+  if_fast_store.JoinContinuation(&if_fast_no_store_continuation);
+
+  // Bailout to runtime call for slow case.
+  IfBuilder if_no_fast_store(this, &if_fast_no_store_continuation);
+  if_no_fast_store.Then();
+  {
+    // Nothing else to do.
+  }
+  if_no_fast_store.Else();
+  {
+    // Slow case, call runtime.
+    HInstruction* lang_mode = Add<HConstant>(casted_stub()->language_mode());
+    Add<HPushArguments>(script_context, slot_index, name, value);
+    Add<HPushArguments>(lang_mode);
+    Add<HCallRuntime>(isolate()->factory()->empty_string(),
+                      Runtime::FunctionForId(Runtime::kStoreGlobalViaContext),
+                      5);
+  }
+  if_no_fast_store.End();
+  return value;
+}
+
+
+Handle<Code> StoreGlobalViaContextStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
   HValue* value = GetParameter(ElementsTransitionAndStoreStub::kValueIndex);
   HValue* map = GetParameter(ElementsTransitionAndStoreStub::kMapIndex);
index bcc1fe88014d9bcd52a61df4bef62c1131e497a7..a1889ad5a9cf0f952dc215db00198f1e7d3501cb 100644 (file)
@@ -19,6 +19,12 @@ namespace v8 {
 namespace internal {
 
 
+RUNTIME_FUNCTION(UnexpectedStubMiss) {
+  FATAL("Unexpected deopt of a stub");
+  return Smi::FromInt(0);
+}
+
+
 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
     : call_descriptor_(stub->GetCallInterfaceDescriptor()),
       stack_parameter_count_(no_reg),
@@ -720,6 +726,20 @@ void RegExpConstructResultStub::InitializeDescriptor(
 }
 
 
+void LoadGlobalViaContextStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  // Must never deoptimize.
+  descriptor->Initialize(FUNCTION_ADDR(UnexpectedStubMiss));
+}
+
+
+void StoreGlobalViaContextStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  // Must never deoptimize.
+  descriptor->Initialize(FUNCTION_ADDR(UnexpectedStubMiss));
+}
+
+
 void TransitionElementsKindStub::InitializeDescriptor(
     CodeStubDescriptor* descriptor) {
   descriptor->Initialize(
index 30624ea4aab18214ab2571eea01ebcb20d2082e9..812b128ad6ffa4151b1ba79342683f63d7c2774d 100644 (file)
@@ -78,6 +78,7 @@ namespace internal {
   V(InternalArrayNoArgumentConstructor)     \
   V(InternalArraySingleArgumentConstructor) \
   V(KeyedLoadGeneric)                       \
+  V(LoadGlobalViaContext)                   \
   V(LoadScriptContextField)                 \
   V(LoadDictionaryElement)                  \
   V(NameDictionaryLookup)                   \
@@ -85,6 +86,7 @@ namespace internal {
   V(Typeof)                                 \
   V(RegExpConstructResult)                  \
   V(StoreFastElement)                       \
+  V(StoreGlobalViaContext)                  \
   V(StoreScriptContextField)                \
   V(StringAdd)                              \
   V(ToBoolean)                              \
@@ -1385,6 +1387,60 @@ class StoreGlobalStub : public HandlerStub {
 };
 
 
+class LoadGlobalViaContextStub : public HydrogenCodeStub {
+ public:
+  // Use the loop version for depths higher than this one.
+  static const int kDynamicDepth = 7;
+
+  LoadGlobalViaContextStub(Isolate* isolate, int depth)
+      : HydrogenCodeStub(isolate) {
+    if (depth > kDynamicDepth) depth = kDynamicDepth;
+    set_sub_minor_key(DepthBits::encode(depth));
+  }
+
+  int depth() const { return DepthBits::decode(sub_minor_key()); }
+
+ private:
+  class DepthBits : public BitField<unsigned int, 0, 3> {};
+  STATIC_ASSERT(kDynamicDepth <= DepthBits::kMax);
+
+  DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadGlobalViaContext);
+  DEFINE_HYDROGEN_CODE_STUB(LoadGlobalViaContext, HydrogenCodeStub);
+};
+
+
+class StoreGlobalViaContextStub : public HydrogenCodeStub {
+ public:
+  // Use the loop version for depths higher than this one.
+  static const int kDynamicDepth = 7;
+
+  StoreGlobalViaContextStub(Isolate* isolate, int depth,
+                            LanguageMode language_mode)
+      : HydrogenCodeStub(isolate) {
+    if (depth > kDynamicDepth) depth = kDynamicDepth;
+    set_sub_minor_key(DepthBits::encode(depth) |
+                      LanguageModeBits::encode(language_mode));
+  }
+
+  int depth() const { return DepthBits::decode(sub_minor_key()); }
+
+  LanguageMode language_mode() const {
+    return LanguageModeBits::decode(sub_minor_key());
+  }
+
+ private:
+  class DepthBits : public BitField<unsigned int, 0, 4> {};
+  STATIC_ASSERT(kDynamicDepth <= DepthBits::kMax);
+
+  class LanguageModeBits : public BitField<LanguageMode, 4, 2> {};
+  STATIC_ASSERT(LANGUAGE_END == 3);
+
+ private:
+  DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreGlobalViaContext);
+  DEFINE_HYDROGEN_CODE_STUB(StoreGlobalViaContext, HydrogenCodeStub);
+};
+
+
 class CallApiFunctionStub : public PlatformCodeStub {
  public:
   explicit CallApiFunctionStub(Isolate* isolate, bool call_data_undefined)
index 4c76b76881f4f298544bd1fb55b9fd77374b5024..c8b0a2daac836b9eab02c05aa6b41b2e8b7a1336 100644 (file)
@@ -3264,9 +3264,23 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
     case VariableLocation::GLOBAL:
     case VariableLocation::UNALLOCATED: {
       // Global var, const, or let variable.
+      Node* script_context = current_context();
+      int slot_index = -1;
+      if (variable->index() > 0) {
+        DCHECK(variable->IsStaticGlobalObjectProperty());
+        // Each var occupies two slots in the context: for reads and writes.
+        slot_index = variable->index();
+        int depth = current_scope()->ContextChainLength(variable->scope());
+        if (depth > 0) {
+          const Operator* op = javascript()->LoadContext(
+              depth - 1, Context::PREVIOUS_INDEX, true);
+          script_context = NewNode(op, current_context());
+        }
+      }
       Node* global = BuildLoadGlobalObject();
       Handle<Name> name = variable->name();
-      Node* value = BuildGlobalLoad(global, name, feedback, contextual_mode);
+      Node* value = BuildGlobalLoad(script_context, global, name, feedback,
+                                    contextual_mode, slot_index);
       states.AddToNode(value, bailout_id, combine);
       return value;
     }
@@ -3404,10 +3418,24 @@ Node* AstGraphBuilder::BuildVariableAssignment(
     case VariableLocation::GLOBAL:
     case VariableLocation::UNALLOCATED: {
       // Global var, const, or let variable.
+      Node* script_context = current_context();
+      int slot_index = -1;
+      if (variable->index() > 0) {
+        DCHECK(variable->IsStaticGlobalObjectProperty());
+        // Each var occupies two slots in the context: for reads and writes.
+        slot_index = variable->index();
+        int depth = current_scope()->ContextChainLength(variable->scope());
+        if (depth > 0) {
+          const Operator* op = javascript()->LoadContext(
+              depth - 1, Context::PREVIOUS_INDEX, true);
+          script_context = NewNode(op, current_context());
+        }
+      }
       Node* global = BuildLoadGlobalObject();
       Handle<Name> name = variable->name();
-      Node* store = BuildGlobalStore(global, name, value, feedback,
-                                     TypeFeedbackId::None());
+      Node* store =
+          BuildGlobalStore(script_context, global, name, value, feedback,
+                           TypeFeedbackId::None(), slot_index);
       states.AddToNode(store, bailout_id, combine);
       return store;
     }
@@ -3611,23 +3639,25 @@ Node* AstGraphBuilder::BuildNamedSuperStore(Node* receiver, Node* home_object,
 }
 
 
-Node* AstGraphBuilder::BuildGlobalLoad(Node* object, Handle<Name> name,
+Node* AstGraphBuilder::BuildGlobalLoad(Node* script_context, Node* global,
+                                       Handle<Name> name,
                                        const VectorSlotPair& feedback,
-                                       ContextualMode mode) {
+                                       ContextualMode mode, int slot_index) {
   const Operator* op =
-      javascript()->LoadGlobal(MakeUnique(name), feedback, mode);
-  Node* node = NewNode(op, object, BuildLoadFeedbackVector());
+      javascript()->LoadGlobal(MakeUnique(name), feedback, mode, slot_index);
+  Node* node = NewNode(op, script_context, global, BuildLoadFeedbackVector());
   return Record(js_type_feedback_, node, feedback.slot());
 }
 
 
-Node* AstGraphBuilder::BuildGlobalStore(Node* object, Handle<Name> name,
-                                        Node* value,
+Node* AstGraphBuilder::BuildGlobalStore(Node* script_context, Node* global,
+                                        Handle<Name> name, Node* value,
                                         const VectorSlotPair& feedback,
-                                        TypeFeedbackId id) {
-  const Operator* op =
-      javascript()->StoreGlobal(language_mode(), MakeUnique(name), feedback);
-  Node* node = NewNode(op, object, value, BuildLoadFeedbackVector());
+                                        TypeFeedbackId id, int slot_index) {
+  const Operator* op = javascript()->StoreGlobal(
+      language_mode(), MakeUnique(name), feedback, slot_index);
+  Node* node =
+      NewNode(op, script_context, global, value, BuildLoadFeedbackVector());
   if (FLAG_vector_stores) {
     return Record(js_type_feedback_, node, feedback.slot());
   }
@@ -3921,7 +3951,7 @@ Node** AstGraphBuilder::EnsureInputBufferSize(int size) {
 
 Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
                                 Node** value_inputs, bool incomplete) {
-  DCHECK(op->ValueInputCount() == value_input_count);
+  DCHECK_EQ(op->ValueInputCount(), value_input_count);
 
   bool has_context = OperatorProperties::HasContextInput(op);
   int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
index 07de774c45bca73e69bc0048888c814d28cdce50..47a6197e5d22409a8b83f21e3f10c1962f2a0330 100644 (file)
@@ -307,10 +307,12 @@ class AstGraphBuilder : public AstVisitor {
                             const VectorSlotPair& feedback);
 
   // Builders for global variable loads and stores.
-  Node* BuildGlobalLoad(Node* global, Handle<Name> name,
-                        const VectorSlotPair& feedback, ContextualMode mode);
-  Node* BuildGlobalStore(Node* global, Handle<Name> name, Node* value,
-                         const VectorSlotPair& feedback, TypeFeedbackId id);
+  Node* BuildGlobalLoad(Node* script_context, Node* global, Handle<Name> name,
+                        const VectorSlotPair& feedback, ContextualMode mode,
+                        int slot_index);
+  Node* BuildGlobalStore(Node* script_context, Node* global, Handle<Name> name,
+                         Node* value, const VectorSlotPair& feedback,
+                         TypeFeedbackId id, int slot_index);
 
   // Builders for accessing the function context.
   Node* BuildLoadBuiltinsObject();
index da42aba523c3f635bf22e3caedf2b5c17497410b..1dbe382cfd29b26f4550d9ee3e6fd864a774f18f 100644 (file)
@@ -334,12 +334,24 @@ void JSGenericLowering::LowerJSLoadNamed(Node* node) {
 
 void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
-  const LoadNamedParameters& p = LoadGlobalParametersOf(node->op());
-  Callable callable = CodeFactory::LoadICInOptimizedCode(
-      isolate(), p.contextual_mode(), SLOPPY, UNINITIALIZED);
-  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
-  node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
-  ReplaceWithStubCall(node, callable, flags);
+  const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
+  if (p.slot_index() >= 0) {
+    Callable callable = CodeFactory::LoadGlobalViaContext(isolate(), 0);
+    Node* script_context = node->InputAt(0);
+    node->ReplaceInput(0, jsgraph()->SmiConstant(0));
+    node->ReplaceInput(1, jsgraph()->SmiConstant(p.slot_index()));
+    node->ReplaceInput(2, jsgraph()->HeapConstant(p.name()));
+    node->ReplaceInput(3, script_context);  // Replace old context.
+    ReplaceWithStubCall(node, callable, flags);
+
+  } else {
+    Callable callable = CodeFactory::LoadICInOptimizedCode(
+        isolate(), p.contextual_mode(), SLOPPY, UNINITIALIZED);
+    node->RemoveInput(0);  // script context
+    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
+    node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
+    ReplaceWithStubCall(node, callable, flags);
+  }
 }
 
 
@@ -379,17 +391,33 @@ void JSGenericLowering::LowerJSStoreNamed(Node* node) {
 
 void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
-  const StoreNamedParameters& p = StoreGlobalParametersOf(node->op());
-  Callable callable = CodeFactory::StoreIC(isolate(), p.language_mode());
-  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
-  if (FLAG_vector_stores) {
-    DCHECK(p.feedback().index() != -1);
-    node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
+  const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
+  if (p.slot_index() >= 0) {
+    Callable callable =
+        CodeFactory::StoreGlobalViaContext(isolate(), 0, p.language_mode());
+    Node* script_context = node->InputAt(0);
+    Node* value = node->InputAt(2);
+    node->ReplaceInput(0, jsgraph()->SmiConstant(0));
+    node->ReplaceInput(1, jsgraph()->SmiConstant(p.slot_index()));
+    node->ReplaceInput(2, jsgraph()->HeapConstant(p.name()));
+    node->ReplaceInput(3, value);
+    node->ReplaceInput(4, script_context);  // Replace old context.
+    ReplaceWithStubCall(node, callable, flags);
+
   } else {
-    node->RemoveInput(3);
+    Callable callable = CodeFactory::StoreIC(isolate(), p.language_mode());
+    node->RemoveInput(0);  // script context
+    node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
+    if (FLAG_vector_stores) {
+      DCHECK(p.feedback().index() != -1);
+      node->InsertInput(zone(), 3,
+                        jsgraph()->SmiConstant(p.feedback().index()));
+    } else {
+      node->RemoveInput(3);
+    }
+    ReplaceWithStubCall(node, callable,
+                        CallDescriptor::kPatchableCallSite | flags);
   }
-  ReplaceWithStubCall(node, callable,
-                      CallDescriptor::kPatchableCallSite | flags);
 }
 
 
index 1966724a86a1ab2df7a5cfe5579e79ee51e70e3b..a0f3d3972ed3dd8a165b5056325598ee6537942a 100644 (file)
@@ -256,9 +256,66 @@ const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) {
 }
 
 
-const LoadNamedParameters& LoadGlobalParametersOf(const Operator* op) {
+bool operator==(LoadGlobalParameters const& lhs,
+                LoadGlobalParameters const& rhs) {
+  return lhs.name() == rhs.name() && lhs.feedback() == rhs.feedback() &&
+         lhs.contextual_mode() == rhs.contextual_mode() &&
+         lhs.slot_index() == rhs.slot_index();
+}
+
+
+bool operator!=(LoadGlobalParameters const& lhs,
+                LoadGlobalParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(LoadGlobalParameters const& p) {
+  return base::hash_combine(p.name(), p.contextual_mode(), p.slot_index());
+}
+
+
+std::ostream& operator<<(std::ostream& os, LoadGlobalParameters const& p) {
+  return os << Brief(*p.name().handle()) << ", " << p.contextual_mode()
+            << ", slot: " << p.slot_index();
+}
+
+
+const LoadGlobalParameters& LoadGlobalParametersOf(const Operator* op) {
   DCHECK_EQ(IrOpcode::kJSLoadGlobal, op->opcode());
-  return OpParameter<LoadNamedParameters>(op);
+  return OpParameter<LoadGlobalParameters>(op);
+}
+
+
+bool operator==(StoreGlobalParameters const& lhs,
+                StoreGlobalParameters const& rhs) {
+  return lhs.language_mode() == rhs.language_mode() &&
+         lhs.name() == rhs.name() && lhs.feedback() == rhs.feedback() &&
+         lhs.slot_index() == rhs.slot_index();
+}
+
+
+bool operator!=(StoreGlobalParameters const& lhs,
+                StoreGlobalParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(StoreGlobalParameters const& p) {
+  return base::hash_combine(p.language_mode(), p.name(), p.feedback(),
+                            p.slot_index());
+}
+
+
+std::ostream& operator<<(std::ostream& os, StoreGlobalParameters const& p) {
+  return os << p.language_mode() << ", " << Brief(*p.name().handle())
+            << ", slot: " << p.slot_index();
+}
+
+
+const StoreGlobalParameters& StoreGlobalParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSStoreGlobal, op->opcode());
+  return OpParameter<StoreGlobalParameters>(op);
 }
 
 
@@ -291,12 +348,6 @@ const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
 }
 
 
-const StoreNamedParameters& StoreGlobalParametersOf(const Operator* op) {
-  DCHECK_EQ(IrOpcode::kJSStoreGlobal, op->opcode());
-  return OpParameter<StoreNamedParameters>(op);
-}
-
-
 bool operator==(StorePropertyParameters const& lhs,
                 StorePropertyParameters const& rhs) {
   return lhs.language_mode() == rhs.language_mode() &&
@@ -568,24 +619,26 @@ const Operator* JSOperatorBuilder::DeleteProperty(LanguageMode language_mode) {
 
 const Operator* JSOperatorBuilder::LoadGlobal(const Unique<Name>& name,
                                               const VectorSlotPair& feedback,
-                                              ContextualMode contextual_mode) {
-  LoadNamedParameters parameters(name, feedback, SLOPPY, contextual_mode);
-  return new (zone()) Operator1<LoadNamedParameters>(    // --
+                                              ContextualMode contextual_mode,
+                                              int slot_index) {
+  LoadGlobalParameters parameters(name, feedback, contextual_mode, slot_index);
+  return new (zone()) Operator1<LoadGlobalParameters>(   // --
       IrOpcode::kJSLoadGlobal, Operator::kNoProperties,  // opcode
       "JSLoadGlobal",                                    // name
-      2, 1, 1, 1, 1, 2,                                  // counts
+      3, 1, 1, 1, 1, 2,                                  // counts
       parameters);                                       // parameter
 }
 
 
 const Operator* JSOperatorBuilder::StoreGlobal(LanguageMode language_mode,
                                                const Unique<Name>& name,
-                                               const VectorSlotPair& feedback) {
-  StoreNamedParameters parameters(language_mode, feedback, name);
-  return new (zone()) Operator1<StoreNamedParameters>(    // --
+                                               const VectorSlotPair& feedback,
+                                               int slot_index) {
+  StoreGlobalParameters parameters(language_mode, feedback, name, slot_index);
+  return new (zone()) Operator1<StoreGlobalParameters>(   // --
       IrOpcode::kJSStoreGlobal, Operator::kNoProperties,  // opcode
       "JSStoreGlobal",                                    // name
-      3, 1, 1, 0, 1, 2,                                   // counts
+      4, 1, 1, 0, 1, 2,                                   // counts
       parameters);                                        // parameter
 }
 
index d70c8e2096186a4dc8577985d2cf74d4858a3851..3f00b475f131d14cec44c0acbd0f4b5e72b43517 100644 (file)
@@ -233,7 +233,7 @@ DynamicContextAccess const& DynamicContextAccessOf(Operator const*);
 
 
 // Defines the property being loaded from an object by a named load. This is
-// used as a parameter by JSLoadNamed and JSLoadGlobal operators.
+// used as a parameter by JSLoadNamed operators.
 class LoadNamedParameters final {
  public:
   LoadNamedParameters(const Unique<Name>& name, const VectorSlotPair& feedback,
@@ -266,7 +266,74 @@ std::ostream& operator<<(std::ostream&, LoadNamedParameters const&);
 
 const LoadNamedParameters& LoadNamedParametersOf(const Operator* op);
 
-const LoadNamedParameters& LoadGlobalParametersOf(const Operator* op);
+
+// Defines the property being loaded from an object by a named load. This is
+// used as a parameter by JSLoadGlobal operator.
+class LoadGlobalParameters final {
+ public:
+  LoadGlobalParameters(const Unique<Name>& name, const VectorSlotPair& feedback,
+                       ContextualMode contextual_mode, int slot_index)
+      : name_(name),
+        feedback_(feedback),
+        contextual_mode_(contextual_mode),
+        slot_index_(slot_index) {}
+
+  const Unique<Name>& name() const { return name_; }
+  ContextualMode contextual_mode() const { return contextual_mode_; }
+
+  const VectorSlotPair& feedback() const { return feedback_; }
+
+  const int slot_index() const { return slot_index_; }
+
+ private:
+  const Unique<Name> name_;
+  const VectorSlotPair feedback_;
+  const ContextualMode contextual_mode_;
+  const int slot_index_;
+};
+
+bool operator==(LoadGlobalParameters const&, LoadGlobalParameters const&);
+bool operator!=(LoadGlobalParameters const&, LoadGlobalParameters const&);
+
+size_t hash_value(LoadGlobalParameters const&);
+
+std::ostream& operator<<(std::ostream&, LoadGlobalParameters const&);
+
+const LoadGlobalParameters& LoadGlobalParametersOf(const Operator* op);
+
+
+// Defines the property being stored to an object by a named store. This is
+// used as a parameter by JSStoreGlobal operator.
+class StoreGlobalParameters final {
+ public:
+  StoreGlobalParameters(LanguageMode language_mode,
+                        const VectorSlotPair& feedback,
+                        const Unique<Name>& name, int slot_index)
+      : language_mode_(language_mode),
+        name_(name),
+        feedback_(feedback),
+        slot_index_(slot_index) {}
+
+  LanguageMode language_mode() const { return language_mode_; }
+  const VectorSlotPair& feedback() const { return feedback_; }
+  const Unique<Name>& name() const { return name_; }
+  int slot_index() const { return slot_index_; }
+
+ private:
+  const LanguageMode language_mode_;
+  const Unique<Name> name_;
+  const VectorSlotPair feedback_;
+  int slot_index_;
+};
+
+bool operator==(StoreGlobalParameters const&, StoreGlobalParameters const&);
+bool operator!=(StoreGlobalParameters const&, StoreGlobalParameters const&);
+
+size_t hash_value(StoreGlobalParameters const&);
+
+std::ostream& operator<<(std::ostream&, StoreGlobalParameters const&);
+
+const StoreGlobalParameters& StoreGlobalParametersOf(const Operator* op);
 
 
 // Defines the property being loaded from an object. This is
@@ -297,7 +364,7 @@ const LoadPropertyParameters& LoadPropertyParametersOf(const Operator* op);
 
 
 // Defines the property being stored to an object by a named store. This is
-// used as a parameter by JSStoreNamed and JSStoreGlobal operators.
+// used as a parameter by JSStoreNamed operator.
 class StoreNamedParameters final {
  public:
   StoreNamedParameters(LanguageMode language_mode,
@@ -323,8 +390,6 @@ std::ostream& operator<<(std::ostream&, StoreNamedParameters const&);
 
 const StoreNamedParameters& StoreNamedParametersOf(const Operator* op);
 
-const StoreNamedParameters& StoreGlobalParametersOf(const Operator* op);
-
 
 // Defines the property being stored to an object. This is used as a parameter
 // by JSStoreProperty operators.
@@ -445,10 +510,12 @@ class JSOperatorBuilder final : public ZoneObject {
 
   const Operator* LoadGlobal(const Unique<Name>& name,
                              const VectorSlotPair& feedback,
-                             ContextualMode contextual_mode = NOT_CONTEXTUAL);
+                             ContextualMode contextual_mode = NOT_CONTEXTUAL,
+                             int slot_index = -1);
   const Operator* StoreGlobal(LanguageMode language_mode,
                               const Unique<Name>& name,
-                              const VectorSlotPair& feedback);
+                              const VectorSlotPair& feedback,
+                              int slot_index = -1);
 
   const Operator* LoadContext(size_t depth, size_t index, bool immutable);
   const Operator* StoreContext(size_t depth, size_t index);
index 4c69c3747ec08507f9de2d2bd5680d7b41f0fe7c..6940a61b0dc98f290975112391fc30bd8dc129bb 100644 (file)
@@ -1023,8 +1023,8 @@ Reduction JSTypedLowering::ReduceJSLoadDynamicGlobal(Node* node) {
       javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true), context,
       context, effect);
   Node* fast = graph()->NewNode(
-      javascript()->LoadGlobal(name, access.feedback(), access.mode()), global,
-      vector, context, state1, state2, global, check_true);
+      javascript()->LoadGlobal(name, access.feedback(), access.mode()), context,
+      global, vector, context, state1, state2, global, check_true);
 
   // Slow case, because variable potentially shadowed. Perform dynamic lookup.
   uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
index 2771671c315a7f0f4da1baf791842491639342ba..28174231ff5d623c286f4073fcdceea319898e3d 100644 (file)
@@ -665,6 +665,7 @@ DEFINE_BOOL(use_idle_notification, true,
 DEFINE_BOOL(use_ic, true, "use inline caching")
 DEFINE_BOOL(trace_ic, false, "trace inline cache state transitions")
 DEFINE_BOOL(vector_stores, false, "use vectors for store ics")
+DEFINE_BOOL(global_var_shortcuts, false, "use ic-less global loads and stores")
 
 // macro-assembler-ia32.cc
 DEFINE_BOOL(native_code_counters, false,
index 2cac0eb460a82b4a7b046091b8b1314624ca036f..21e532b76a63bfa5cbc159797ee9742de1fc7513 100644 (file)
@@ -6069,6 +6069,11 @@ class HObjectAccess final {
     return HObjectAccess(kInobject, PropertyCell::kValueOffset);
   }
 
+  static HObjectAccess ForPropertyCellDetails() {
+    return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
+                         Representation::Smi());
+  }
+
   static HObjectAccess ForCellValue() {
     return HObjectAccess(kInobject, Cell::kValueOffset);
   }
index 82b827079dfc553e439d45c265da55bd9118e2a5..d747cfb52d2b5106a322b7eaad59758ab7df3a3e 100644 (file)
@@ -339,7 +339,7 @@ void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
     DCHECK(IsLoopHeader() || first_ == NULL);
     HEnvironment* incoming_env = pred->last_environment();
     if (IsLoopHeader()) {
-      DCHECK(phis()->length() == incoming_env->length());
+      DCHECK_EQ(phis()->length(), incoming_env->length());
       for (int i = 0; i < phis_.length(); ++i) {
         phis_[i]->AddInput(incoming_env->values()->at(i));
       }
@@ -997,6 +997,13 @@ void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
 }
 
 
+void HGraphBuilder::IfBuilder::EndUnreachable() {
+  if (captured_) return;
+  Finish();
+  builder()->set_current_block(nullptr);
+}
+
+
 void HGraphBuilder::IfBuilder::End() {
   if (captured_) return;
   Finish();
@@ -3134,6 +3141,17 @@ void HGraphBuilder::BuildCreateAllocationMemento(
 }
 
 
+HInstruction* HGraphBuilder::BuildGetNativeContext() {
+  // Get the global object, then the native context
+  HValue* global_object = Add<HLoadNamedField>(
+      context(), nullptr,
+      HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
+  return Add<HLoadNamedField>(global_object, nullptr,
+                              HObjectAccess::ForObservableJSObjectOffset(
+                                  GlobalObject::kNativeContextOffset));
+}
+
+
 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
   // Get the global object, then the native context
   HInstruction* context = Add<HLoadNamedField>(
@@ -3157,14 +3175,51 @@ HInstruction* HGraphBuilder::BuildGetScriptContext(int context_index) {
 }
 
 
-HInstruction* HGraphBuilder::BuildGetNativeContext() {
-  // Get the global object, then the native context
-  HValue* global_object = Add<HLoadNamedField>(
-      context(), nullptr,
-      HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
-  return Add<HLoadNamedField>(global_object, nullptr,
-                              HObjectAccess::ForObservableJSObjectOffset(
-                                  GlobalObject::kNativeContextOffset));
+HValue* HGraphBuilder::BuildGetParentContext(HValue* depth, int depth_value) {
+  HValue* script_context = context();
+  if (depth != NULL) {
+    HValue* zero = graph()->GetConstant0();
+
+    Push(script_context);
+    Push(depth);
+
+    LoopBuilder loop(this);
+    loop.BeginBody(2);  // Drop script_context and depth from last environment
+                        // to appease live range building without simulates.
+    depth = Pop();
+    script_context = Pop();
+
+    script_context = Add<HLoadNamedField>(
+        script_context, nullptr,
+        HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+    depth = AddUncasted<HSub>(depth, graph()->GetConstant1());
+    depth->ClearFlag(HValue::kCanOverflow);
+
+    IfBuilder if_break(this);
+    if_break.If<HCompareNumericAndBranch, HValue*>(depth, zero, Token::EQ);
+    if_break.Then();
+    {
+      Push(script_context);  // The result.
+      loop.Break();
+    }
+    if_break.Else();
+    {
+      Push(script_context);
+      Push(depth);
+    }
+    loop.EndBody();
+    if_break.End();
+
+    script_context = Pop();
+  } else if (depth_value > 0) {
+    // Unroll the above loop.
+    for (int i = 0; i < depth_value; i++) {
+      script_context = Add<HLoadNamedField>(
+          script_context, nullptr,
+          HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+    }
+  }
+  return script_context;
 }
 
 
index 65e54e652b55937524f7171f120c9a6270c59531..21c3ad3caf2062655e6897b995a46c6593cd92fb 100644 (file)
@@ -1596,6 +1596,7 @@ class HGraphBuilder {
     void Then();
     void Else();
     void End();
+    void EndUnreachable();
 
     void Deopt(Deoptimizer::DeoptReason reason);
     void ThenDeopt(Deoptimizer::DeoptReason reason) {
@@ -1860,6 +1861,10 @@ class HGraphBuilder {
   HInstruction* BuildGetNativeContext(HValue* closure);
   HInstruction* BuildGetNativeContext();
   HInstruction* BuildGetScriptContext(int context_index);
+  // Builds a loop version if |depth| is specified or unrolls the loop to
+  // |depth_value| iterations otherwise.
+  HValue* BuildGetParentContext(HValue* depth, int depth_value);
+
   HInstruction* BuildGetArrayFunction();
   HValue* BuildArrayBufferViewFieldAccessor(HValue* object,
                                             HValue* checked_object,
index 6bd74016ec4c6d7834b75de607b9b049bab08ef5..cc4c74dc2f06129863e8bd2620acc3a15fbe319a 100644 (file)
@@ -1417,13 +1417,29 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ mov(LoadDescriptor::NameRegister(), var->name());
-  __ mov(LoadDescriptor::SlotRegister(),
-         Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+           Immediate(Smi::FromInt(depth)));
+    __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+           Immediate(Smi::FromInt(slot_index)));
+    __ mov(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ mov(LoadDescriptor::NameRegister(), var->name());
+    __ mov(LoadDescriptor::SlotRegister(),
+           Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2658,13 +2674,29 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ mov(StoreDescriptor::NameRegister(), var->name());
     __ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+           Immediate(Smi::FromInt(depth)));
+    __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+           Immediate(Smi::FromInt(slot_index)));
+    __ mov(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index be0b2cd17f92dbd38df9291cef556d5f50f202ec..9c87d324f192bdf2777a6d118035b9d734800bde 100644 (file)
@@ -35,6 +35,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return ebx; }
 const Register StoreTransitionDescriptor::MapRegister() { return ebx; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return ecx; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return ecx; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return eax; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() {
   return ebx;
 }
index 1e8cc2e5a7aae2a7f940f1a49e2d0cfc8b292ed0..3f53b1fbbb62da8603831737528dec84e4f3b43c 100644 (file)
@@ -108,6 +108,46 @@ void StoreTransitionDescriptor::InitializePlatformSpecific(
 }
 
 
+Type::FunctionType*
+LoadGlobalViaContextDescriptor::BuildCallInterfaceDescriptorFunctionType(
+    Isolate* isolate, int paramater_count) {
+  Type::FunctionType* function = Type::FunctionType::New(
+      AnyTagged(), Type::Undefined(), 3, isolate->interface_descriptor_zone());
+  function->InitParameter(0, SmiType());
+  function->InitParameter(1, SmiType());
+  function->InitParameter(2, AnyTagged());
+  return function;
+}
+
+
+void LoadGlobalViaContextDescriptor::InitializePlatformSpecific(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {DepthRegister(), SlotRegister(), NameRegister()};
+  data->InitializePlatformSpecific(arraysize(registers), registers);
+}
+
+
+Type::FunctionType*
+StoreGlobalViaContextDescriptor::BuildCallInterfaceDescriptorFunctionType(
+    Isolate* isolate, int paramater_count) {
+  Type::FunctionType* function = Type::FunctionType::New(
+      AnyTagged(), Type::Undefined(), 5, isolate->interface_descriptor_zone());
+  function->InitParameter(0, SmiType());
+  function->InitParameter(1, SmiType());
+  function->InitParameter(2, AnyTagged());
+  function->InitParameter(3, AnyTagged());
+  return function;
+}
+
+
+void StoreGlobalViaContextDescriptor::InitializePlatformSpecific(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {DepthRegister(), SlotRegister(), NameRegister(),
+                          ValueRegister()};
+  data->InitializePlatformSpecific(arraysize(registers), registers);
+}
+
+
 void ElementTransitionAndStoreDescriptor::InitializePlatformSpecific(
     CallInterfaceDescriptorData* data) {
   Register registers[] = {ValueRegister(), MapRegister(), NameRegister(),
index 7fa70f1b38c8974222feb936e2aedc16b33b8dd1..56cbad219f3a38ecd1bc6ecf915de34bd9fca461 100644 (file)
@@ -57,6 +57,8 @@ class PlatformInterfaceDescriptor;
   V(ApiGetter)                                \
   V(ArgumentsAccessRead)                      \
   V(StoreArrayLiteralElement)                 \
+  V(LoadGlobalViaContext)                     \
+  V(StoreGlobalViaContext)                    \
   V(MathPowTagged)                            \
   V(MathPowInteger)                           \
   V(ContextOnly)                              \
@@ -426,6 +428,29 @@ class RegExpConstructResultDescriptor : public CallInterfaceDescriptor {
 };
 
 
+class LoadGlobalViaContextDescriptor : public CallInterfaceDescriptor {
+ public:
+  DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(LoadGlobalViaContextDescriptor,
+                                               CallInterfaceDescriptor)
+
+  static const Register DepthRegister();
+  static const Register SlotRegister();
+  static const Register NameRegister();
+};
+
+
+class StoreGlobalViaContextDescriptor : public CallInterfaceDescriptor {
+ public:
+  DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(StoreGlobalViaContextDescriptor,
+                                               CallInterfaceDescriptor)
+
+  static const Register DepthRegister();
+  static const Register SlotRegister();
+  static const Register NameRegister();
+  static const Register ValueRegister();
+};
+
+
 class TransitionElementsKindDescriptor : public CallInterfaceDescriptor {
  public:
   DECLARE_DESCRIPTOR(TransitionElementsKindDescriptor, CallInterfaceDescriptor)
index 978c0799f59d19c9bf0e495ec7a22c7e67f391b0..f5d441178f526bfd8b7d280df8d43007bfbe5a82 100644 (file)
@@ -1484,13 +1484,29 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ lw(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
-  __ li(LoadDescriptor::SlotRegister(),
-        Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ li(LoadGlobalViaContextDescriptor::DepthRegister(),
+          Operand(Smi::FromInt(depth)));
+    __ li(LoadGlobalViaContextDescriptor::SlotRegister(),
+          Operand(Smi::FromInt(slot_index)));
+    __ li(LoadGlobalViaContextDescriptor::NameRegister(), Operand(var->name()));
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ lw(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
+    __ li(LoadDescriptor::SlotRegister(),
+          Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2740,7 +2756,7 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ mov(StoreDescriptor::ValueRegister(), result_register());
     __ li(StoreDescriptor::NameRegister(), Operand(var->name()));
@@ -2748,6 +2764,23 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ li(StoreGlobalViaContextDescriptor::DepthRegister(),
+          Operand(Smi::FromInt(depth)));
+    __ li(StoreGlobalViaContextDescriptor::SlotRegister(),
+          Operand(Smi::FromInt(slot_index)));
+    __ li(StoreGlobalViaContextDescriptor::NameRegister(),
+          Operand(var->name()));
+    __ mov(StoreGlobalViaContextDescriptor::ValueRegister(), result_register());
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index 0c00833fb60fbe4cd9a38fce706e6e25597667da..55b86c03b1da3d94aa0f0ed19bfafc07a8e97158 100644 (file)
@@ -36,6 +36,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return a3; }
 const Register StoreTransitionDescriptor::MapRegister() { return a3; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return a3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return a3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return a0; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
 
 
index 97d5a45d846e6afc54785526f52e3c6909bb5bc2..7185c0438c225149db6767513780441f83f55b3d 100644 (file)
@@ -1481,13 +1481,29 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ ld(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
-  __ li(LoadDescriptor::SlotRegister(),
-        Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ li(LoadGlobalViaContextDescriptor::DepthRegister(),
+          Operand(Smi::FromInt(depth)));
+    __ li(LoadGlobalViaContextDescriptor::SlotRegister(),
+          Operand(Smi::FromInt(slot_index)));
+    __ li(LoadGlobalViaContextDescriptor::NameRegister(), Operand(var->name()));
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ ld(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
+    __ li(LoadDescriptor::SlotRegister(),
+          Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2738,7 +2754,7 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ mov(StoreDescriptor::ValueRegister(), result_register());
     __ li(StoreDescriptor::NameRegister(), Operand(var->name()));
@@ -2746,6 +2762,23 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ li(StoreGlobalViaContextDescriptor::DepthRegister(),
+          Operand(Smi::FromInt(depth)));
+    __ li(StoreGlobalViaContextDescriptor::SlotRegister(),
+          Operand(Smi::FromInt(slot_index)));
+    __ li(StoreGlobalViaContextDescriptor::NameRegister(),
+          Operand(var->name()));
+    __ mov(StoreGlobalViaContextDescriptor::ValueRegister(), result_register());
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index 47cc0923cb8f0b7009fededac3770740c295372a..cb596af41478143721020bc6c4da338ab817b751 100644 (file)
@@ -36,6 +36,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return a3; }
 const Register StoreTransitionDescriptor::MapRegister() { return a3; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return a3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return a3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return a0; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
 
 
index f67194d407049a0d0ca6f1f85bb9f85937dce202..1231c15a82228e63f310b60063ac1abd66dcfdbc 100644 (file)
@@ -1462,13 +1462,30 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
-  __ mov(LoadDescriptor::SlotRegister(),
-         Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+           Operand(Smi::FromInt(depth)));
+    __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+           Operand(Smi::FromInt(slot_index)));
+    __ mov(LoadGlobalViaContextDescriptor::NameRegister(),
+           Operand(var->name()));
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+    __ mov(LoadDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2760,13 +2777,30 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ mov(StoreDescriptor::NameRegister(), Operand(var->name()));
     __ LoadP(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+           Operand(Smi::FromInt(depth)));
+    __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+           Operand(Smi::FromInt(slot_index)));
+    __ mov(StoreGlobalViaContextDescriptor::NameRegister(),
+           Operand(var->name()));
+    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(r3));
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index fc1567e8204a56c2d7d2f269c0b6110f7128ea18..f3bf54946ad4eb79cf04bee23137791fdd185af1 100644 (file)
@@ -36,6 +36,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return r6; }
 const Register StoreTransitionDescriptor::MapRegister() { return r6; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return r4; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return r5; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return r3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return r4; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return r5; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return r6; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return r3; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r6; }
 
 
index d27b2b14207910fb33309cdb9d907656573ec5bc..8a3d0a1febdebe758c1c02b6f163837d82894746 100644 (file)
@@ -421,6 +421,70 @@ RUNTIME_FUNCTION(Runtime_ObjectSeal) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_LoadGlobalViaContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(Context, script_context, 0);
+  CONVERT_SMI_ARG_CHECKED(index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+  DCHECK(script_context->IsScriptContext());
+  DCHECK(script_context->get(index)->IsPropertyCell());
+
+  Handle<GlobalObject> global(script_context->global_object());
+
+  LookupIterator it(global, name, LookupIterator::OWN);
+  if (LookupIterator::DATA == it.state()) {
+    // Now update cell in the script context.
+    Handle<PropertyCell> cell = it.GetPropertyCell();
+    script_context->set(index, *cell);
+  } else {
+    // This is not a fast case, so keep this access in a slow mode.
+    // Store empty_property_cell here to release the outdated property cell.
+    script_context->set(index, isolate->heap()->empty_property_cell());
+  }
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
+
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreGlobalViaContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(Context, script_context, 0);
+  CONVERT_SMI_ARG_CHECKED(index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
+  CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode_arg, 4);
+  DCHECK(script_context->IsScriptContext());
+  DCHECK(script_context->get(index)->IsPropertyCell());
+  LanguageMode language_mode = language_mode_arg;
+
+  Handle<GlobalObject> global(script_context->global_object());
+
+  LookupIterator it(global, name, LookupIterator::OWN);
+  if (LookupIterator::DATA == it.state()) {
+    // Now update cell in the script context.
+    Handle<PropertyCell> cell = it.GetPropertyCell();
+    script_context->set(index, *cell);
+  } else {
+    // This is not a fast case, so keep this access in a slow mode.
+    // Store empty_property_cell here to release the outdated property cell.
+    script_context->set(index, isolate->heap()->empty_property_cell());
+  }
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Object::SetProperty(&it, value, language_mode,
+                          Object::CERTAINLY_NOT_STORE_FROM_KEYED));
+
+  return *result;
+}
+
+
 RUNTIME_FUNCTION(Runtime_GetProperty) {
   HandleScope scope(isolate);
   DCHECK(args.length() == 2);
index cad128513d6ccb07bd8a0f8b262c2afe94ded8aa..7e1e3e8714ea8dc0a3715e66d9cfc6a460ebd471 100644 (file)
@@ -438,6 +438,8 @@ namespace internal {
   F(GetPropertyStrong, 2, 1)                         \
   F(KeyedGetProperty, 2, 1)                          \
   F(KeyedGetPropertyStrong, 2, 1)                    \
+  F(LoadGlobalViaContext, 3, 1)                      \
+  F(StoreGlobalViaContext, 5, 1)                     \
   F(AddNamedProperty, 4, 1)                          \
   F(SetProperty, 4, 1)                               \
   F(AddElement, 3, 1)                                \
index f9eef9ab21d990c191df5aee894803c8682700e1..d6a414b32050e2552b3405530fe323b0966e40e2 100644 (file)
@@ -14,9 +14,6 @@
 namespace v8 {
 namespace internal {
 
-// TODO(ishell): remove this once compiler support is landed.
-bool enable_context_globals = false;
-
 // ----------------------------------------------------------------------------
 // Implementation of LocalsMap
 //
@@ -1478,14 +1475,19 @@ void Scope::AllocateDeclaredGlobal(Isolate* isolate, Variable* var) {
   DCHECK(var->scope() == this);
   DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
          !var->IsStackLocal());
-  if (var->IsUnallocated() && var->IsStaticGlobalObjectProperty()) {
-    DCHECK_EQ(-1, var->index());
-    DCHECK(var->name()->IsString());
-    var->AllocateTo(VariableLocation::GLOBAL, num_heap_slots_);
-    num_global_slots_++;
-    // Each global variable occupies two slots in the context: for reads
-    // and writes.
-    num_heap_slots_ += 2;
+  if (var->IsUnallocated()) {
+    if (var->IsStaticGlobalObjectProperty()) {
+      DCHECK_EQ(-1, var->index());
+      DCHECK(var->name()->IsString());
+      var->AllocateTo(VariableLocation::GLOBAL, num_heap_slots_);
+      num_global_slots_++;
+      // Each global variable occupies two slots in the context: for reads
+      // and writes.
+      num_heap_slots_ += 2;
+    } else {
+      // There must be only DYNAMIC_GLOBAL in the script scope.
+      DCHECK(!is_script_scope() || DYNAMIC_GLOBAL == var->mode());
+    }
   }
 }
 
@@ -1513,7 +1515,7 @@ void Scope::AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate) {
     AllocateNonParameterLocal(isolate, vars[i].var());
   }
 
-  if (enable_context_globals) {
+  if (FLAG_global_var_shortcuts) {
     for (int i = 0; i < var_count; i++) {
       AllocateDeclaredGlobal(isolate, vars[i].var());
     }
index eac70192053b5a430d9a982f97ab5f101cd41fa3..1bd1c1425db1e56abc382412e60296663f73b053 100644 (file)
@@ -1454,13 +1454,29 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ Move(LoadDescriptor::NameRegister(), var->name());
-  __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ Move(LoadDescriptor::SlotRegister(),
-          SmiFromSlot(proxy->VariableFeedbackSlot()));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ Move(LoadGlobalViaContextDescriptor::DepthRegister(),
+            Smi::FromInt(depth));
+    __ Move(LoadGlobalViaContextDescriptor::SlotRegister(),
+            Smi::FromInt(slot_index));
+    __ Move(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ Move(LoadDescriptor::NameRegister(), var->name());
+    __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ Move(LoadDescriptor::SlotRegister(),
+            SmiFromSlot(proxy->VariableFeedbackSlot()));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2661,13 +2677,29 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ Move(StoreDescriptor::NameRegister(), var->name());
     __ movp(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ Move(StoreGlobalViaContextDescriptor::DepthRegister(),
+            Smi::FromInt(depth));
+    __ Move(StoreGlobalViaContextDescriptor::SlotRegister(),
+            Smi::FromInt(slot_index));
+    __ Move(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(rax));
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index 4f43569c35caca2ddbbbeaaaba70e7bc2e226325..36f7ea66ff87a8937898b411980f41be99a13a30 100644 (file)
@@ -36,6 +36,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return rbx; }
 const Register StoreTransitionDescriptor::MapRegister() { return rbx; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return rdx; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return rbx; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return rcx; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return rdx; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return rbx; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return rcx; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return rax; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() {
   return rbx;
 }
index 7b1a35dcd72d1dae92c8d8f5827dcebcd9957c52..29616e877c431962372739f4146794b9f44c396c 100644 (file)
@@ -1410,13 +1410,29 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
   Variable* var = proxy->var();
   DCHECK(var->IsUnallocatedOrGlobalSlot() ||
          (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
-  __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
-  __ mov(LoadDescriptor::NameRegister(), var->name());
-  __ mov(LoadDescriptor::SlotRegister(),
-         Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
-  // Inside typeof use a regular load, not a contextual load, to avoid
-  // a reference error.
-  CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  if (var->IsGlobalSlot()) {
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index();
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+           Immediate(Smi::FromInt(depth)));
+    __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+           Immediate(Smi::FromInt(slot_index)));
+    __ mov(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+    LoadGlobalViaContextStub stub(isolate(), depth);
+    __ CallStub(&stub);
+
+  } else {
+    __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ mov(LoadDescriptor::NameRegister(), var->name());
+    __ mov(LoadDescriptor::SlotRegister(),
+           Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    // Inside typeof use a regular load, not a contextual load, to avoid
+    // a reference error.
+    CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+  }
 }
 
 
@@ -2648,13 +2664,29 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
 
 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
                                                FeedbackVectorICSlot slot) {
-  if (var->IsUnallocatedOrGlobalSlot()) {
+  if (var->IsUnallocated()) {
     // Global var, const, or let.
     __ mov(StoreDescriptor::NameRegister(), var->name());
     __ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
     if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
     CallStoreIC();
 
+  } else if (var->IsGlobalSlot()) {
+    // Global var, const, or let.
+    DCHECK(var->index() > 0);
+    DCHECK(var->IsStaticGlobalObjectProperty());
+    // Each var occupies two slots in the context: for reads and writes.
+    int slot_index = var->index() + 1;
+    int depth = scope()->ContextChainLength(var->scope());
+    __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+           Immediate(Smi::FromInt(depth)));
+    __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+           Immediate(Smi::FromInt(slot_index)));
+    __ mov(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
+    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+    __ CallStub(&stub);
+
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
     DCHECK(!var->IsLookupSlot());
index 05fa9b89268e1cfc137cc4a5e1fad83b8ebe2741..97265b1b39fb10a279d9388e7ce74bd283495dff 100644 (file)
@@ -35,6 +35,17 @@ const Register VectorStoreICDescriptor::VectorRegister() { return ebx; }
 const Register StoreTransitionDescriptor::MapRegister() { return ebx; }
 
 
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return ecx; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return ecx; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return eax; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() {
   return ebx;
 }
index d52242ec7df52af7cf508a199a4e8daadab7ad86..251293ddcf3c5d8e0c510832c50e303aeb42e93e 100644 (file)
@@ -85,7 +85,7 @@ class JSTypeFeedbackTest : public TypedGraphTest {
     Unique<Name> name = Unique<Name>::CreateUninitialized(
         isolate()->factory()->InternalizeUtf8String(string));
     const Operator* op = javascript()->LoadGlobal(name, feedback);
-    Node* load = graph()->NewNode(op, global, vector, context);
+    Node* load = graph()->NewNode(op, context, global, vector, context);
     if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) {
       for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op);
            i++) {
index ca2a4a9ec44e73a87e950d71e46dce6fb36bc9a6..ded8f4d08df4ad5030b1516f0acadc39d72ab7c5 100644 (file)
@@ -901,8 +901,8 @@ TEST_F(JSTypedLoweringTest, JSLoadGlobalConstants) {
   for (size_t i = 0; i < arraysize(names); i++) {
     Unique<Name> name = Unique<Name>::CreateImmovable(names[i]);
     Reduction r = Reduce(graph()->NewNode(
-        javascript()->LoadGlobal(name, feedback), global, vector, context,
-        EmptyFrameState(), EmptyFrameState(), effect, control));
+        javascript()->LoadGlobal(name, feedback), context, global, vector,
+        context, EmptyFrameState(), EmptyFrameState(), effect, control));
 
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), matches[i]);