harmony-scoping: Implement StoreIC handler for stores to global contexts.
authordslomov@chromium.org <dslomov@chromium.org>
Tue, 11 Nov 2014 15:15:42 +0000 (15:15 +0000)
committerdslomov@chromium.org <dslomov@chromium.org>
Tue, 11 Nov 2014 15:16:20 +0000 (15:16 +0000)
R=ishell@chromium.org, adamk@chromium.org, rossberg@chromium.org, verwaest@chromium.org
BUG=v8:2198
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#25264}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25264 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/code-stubs-hydrogen.cc
src/code-stubs.h
src/hydrogen.cc
src/hydrogen.h
src/ic/ic.cc
test/cctest/test-decls.cc

index 225e00f..e33b4a8 100644 (file)
@@ -518,13 +518,7 @@ HValue* CodeStubGraphBuilder<LoadGlobalContextFieldStub>::BuildCodeStub() {
   int context_index = casted_stub()->context_index();
   int slot_index = casted_stub()->slot_index();
 
-  HValue* native_context = BuildGetNativeContext();
-  HValue* global_context_table = Add<HLoadNamedField>(
-      native_context, static_cast<HValue*>(NULL),
-      HObjectAccess::ForContextSlot(Context::GLOBAL_CONTEXT_TABLE_INDEX));
-  HValue* global_context =
-      Add<HLoadNamedField>(global_context_table, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForGlobalContext(context_index));
+  HValue* global_context = BuildGetGlobalContext(context_index);
   return Add<HLoadNamedField>(global_context, static_cast<HValue*>(NULL),
                               HObjectAccess::ForContextSlot(slot_index));
 }
@@ -536,6 +530,24 @@ Handle<Code> LoadGlobalContextFieldStub::GenerateCode() {
 
 
 template <>
+HValue* CodeStubGraphBuilder<StoreGlobalContextFieldStub>::BuildCodeStub() {
+  int context_index = casted_stub()->context_index();
+  int slot_index = casted_stub()->slot_index();
+
+  HValue* global_context = BuildGetGlobalContext(context_index);
+  Add<HStoreNamedField>(global_context,
+                        HObjectAccess::ForContextSlot(slot_index),
+                        GetParameter(2), STORE_TO_INITIALIZED_ENTRY);
+  return GetParameter(2);
+}
+
+
+Handle<Code> StoreGlobalContextFieldStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() {
   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
       GetParameter(LoadDescriptor::kReceiverIndex),
index 433e97a..4166d3d 100644 (file)
@@ -77,6 +77,7 @@ namespace internal {
   V(NumberToString)                         \
   V(RegExpConstructResult)                  \
   V(StoreFastElement)                       \
+  V(StoreGlobalContextField)                \
   V(StringAdd)                              \
   V(ToBoolean)                              \
   V(TransitionElementsKind)                 \
@@ -2017,10 +2018,10 @@ class DoubleToIStub : public PlatformCodeStub {
 };
 
 
-class LoadGlobalContextFieldStub : public HandlerStub {
+class GlobalContextFieldStub : public HandlerStub {
  public:
-  LoadGlobalContextFieldStub(
-      Isolate* isolate, const GlobalContextTable::LookupResult* lookup_result)
+  GlobalContextFieldStub(Isolate* isolate,
+                         const GlobalContextTable::LookupResult* lookup_result)
       : HandlerStub(isolate) {
     DCHECK(Accepted(lookup_result));
     set_sub_minor_key(ContextIndexBits::encode(lookup_result->context_index) |
@@ -2045,15 +2046,35 @@ class LoadGlobalContextFieldStub : public HandlerStub {
   class SlotIndexBits
       : public BitField<int, kContextIndexBits, kSlotIndexBits> {};
 
-  virtual Code::Kind kind() const { return Code::LOAD_IC; }
   virtual Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
+  DEFINE_CODE_STUB_BASE(GlobalContextFieldStub, HandlerStub);
+};
 
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
-    return ContextOnlyDescriptor(isolate());
-  }
 
-  DEFINE_HANDLER_CODE_STUB(LoadGlobalContextField, HandlerStub);
+class LoadGlobalContextFieldStub : public GlobalContextFieldStub {
+ public:
+  LoadGlobalContextFieldStub(
+      Isolate* isolate, const GlobalContextTable::LookupResult* lookup_result)
+      : GlobalContextFieldStub(isolate, lookup_result) {}
+
+ private:
+  virtual Code::Kind kind() const OVERRIDE { return Code::LOAD_IC; }
+
+  DEFINE_HANDLER_CODE_STUB(LoadGlobalContextField, GlobalContextFieldStub);
+};
+
+
+class StoreGlobalContextFieldStub : public GlobalContextFieldStub {
+ public:
+  StoreGlobalContextFieldStub(
+      Isolate* isolate, const GlobalContextTable::LookupResult* lookup_result)
+      : GlobalContextFieldStub(isolate, lookup_result) {}
+
+ private:
+  virtual Code::Kind kind() const OVERRIDE { return Code::STORE_IC; }
+
+  DEFINE_HANDLER_CODE_STUB(StoreGlobalContextField, GlobalContextFieldStub);
 };
 
 
index 4b52f26..b9b3eb0 100644 (file)
@@ -3133,6 +3133,16 @@ HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
 }
 
 
+HInstruction* HGraphBuilder::BuildGetGlobalContext(int context_index) {
+  HValue* native_context = BuildGetNativeContext();
+  HValue* global_context_table = Add<HLoadNamedField>(
+      native_context, static_cast<HValue*>(NULL),
+      HObjectAccess::ForContextSlot(Context::GLOBAL_CONTEXT_TABLE_INDEX));
+  return Add<HLoadNamedField>(global_context_table, static_cast<HValue*>(NULL),
+                              HObjectAccess::ForGlobalContext(context_index));
+}
+
+
 HInstruction* HGraphBuilder::BuildGetNativeContext() {
   // Get the global context, then the native context
   HValue* global_object = Add<HLoadNamedField>(
@@ -6522,6 +6532,24 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     HValue* value,
     BailoutId ast_id) {
   Handle<GlobalObject> global(current_info()->global_object());
+
+  if (FLAG_harmony_scoping) {
+    Handle<GlobalContextTable> global_contexts(
+        global->native_context()->global_context_table());
+    GlobalContextTable::LookupResult lookup;
+    if (GlobalContextTable::Lookup(global_contexts, var->name(), &lookup)) {
+      Handle<Context> global_context =
+          GlobalContextTable::GetContext(global_contexts, lookup.context_index);
+      HStoreNamedField* instr = Add<HStoreNamedField>(
+          Add<HConstant>(global_context),
+          HObjectAccess::ForContextSlot(lookup.slot_index), value);
+      USE(instr);
+      DCHECK(instr->HasObservableSideEffects());
+      Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
+      return;
+    }
+  }
+
   LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR);
   GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE);
   if (type == kUseCell) {
index 0ff5a45..207244d 100644 (file)
@@ -1878,6 +1878,7 @@ class HGraphBuilder {
 
   HInstruction* BuildGetNativeContext(HValue* closure);
   HInstruction* BuildGetNativeContext();
+  HInstruction* BuildGetGlobalContext(int context_index);
   HInstruction* BuildGetArrayFunction();
 
  protected:
index 810a149..82d48a2 100644 (file)
@@ -1396,6 +1396,13 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
       if (lookup_result.mode == CONST) {
         return TypeError("harmony_const_assign", object, name);
       }
+
+      if (FLAG_use_ic &&
+          StoreGlobalContextFieldStub::Accepted(&lookup_result)) {
+        StoreGlobalContextFieldStub stub(isolate(), &lookup_result);
+        PatchCache(name, stub.GetCode());
+      }
+
       global_context->set(lookup_result.slot_index, *value);
       return value;
     }
index ab5f192..94788fc 100644 (file)
@@ -1008,7 +1008,7 @@ TEST(CrossScriptStaticLookupUndeclared) {
 }
 
 
-TEST(CrossScriptICs) {
+TEST(CrossScriptLoadICs) {
   i::FLAG_harmony_scoping = true;
   i::FLAG_allow_natives_syntax = true;
 
@@ -1062,3 +1062,81 @@ TEST(CrossScriptICs) {
                   Number::New(CcTest::isolate(), 5));
   }
 }
+
+
+TEST(CrossScriptStoreICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "function g(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(7); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 7));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g(31); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 31));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(32); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 32));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(g); g(18); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 18));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(33); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 33));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(18); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 18));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f(20); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(8); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 8));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(13); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 13));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(41); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 41));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+  }
+}