harmony-scoping: Implement LoadIC handler for loads from global contexts.
authordslomov@chromium.org <dslomov@chromium.org>
Tue, 11 Nov 2014 11:16:30 +0000 (11:16 +0000)
committerdslomov@chromium.org <dslomov@chromium.org>
Tue, 11 Nov 2014 11:16:43 +0000 (11: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/696783005

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

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

index 45d1417b0de1d5b2e50c0d9b64eb3af0454bb695..225e00f5a49daf4ddebd84734bbc0946b5891661 100644 (file)
@@ -513,6 +513,28 @@ Handle<Code> CreateAllocationSiteStub::GenerateCode() {
 }
 
 
+template <>
+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));
+  return Add<HLoadNamedField>(global_context, static_cast<HValue*>(NULL),
+                              HObjectAccess::ForContextSlot(slot_index));
+}
+
+
+Handle<Code> LoadGlobalContextFieldStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
 template <>
 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() {
   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
index af5ae8d2a5d1fbe16f3f72f8764f9eaed70c7da4..433e97aff092c4f00ae0ec6e334dac179c9d2e83 100644 (file)
@@ -69,6 +69,7 @@ namespace internal {
   V(InternalArrayNoArgumentConstructor)     \
   V(InternalArraySingleArgumentConstructor) \
   V(KeyedLoadGeneric)                       \
+  V(LoadGlobalContextField)                 \
   V(LoadDictionaryElement)                  \
   V(LoadFastElement)                        \
   V(MegamorphicLoad)                        \
@@ -2016,6 +2017,46 @@ class DoubleToIStub : public PlatformCodeStub {
 };
 
 
+class LoadGlobalContextFieldStub : public HandlerStub {
+ public:
+  LoadGlobalContextFieldStub(
+      Isolate* isolate, const GlobalContextTable::LookupResult* lookup_result)
+      : HandlerStub(isolate) {
+    DCHECK(Accepted(lookup_result));
+    set_sub_minor_key(ContextIndexBits::encode(lookup_result->context_index) |
+                      SlotIndexBits::encode(lookup_result->slot_index));
+  }
+
+  int context_index() const {
+    return ContextIndexBits::decode(sub_minor_key());
+  }
+
+  int slot_index() const { return SlotIndexBits::decode(sub_minor_key()); }
+
+  static bool Accepted(const GlobalContextTable::LookupResult* lookup_result) {
+    return ContextIndexBits::is_valid(lookup_result->context_index) &&
+           SlotIndexBits::is_valid(lookup_result->slot_index);
+  }
+
+ private:
+  static const int kContextIndexBits = 13;
+  static const int kSlotIndexBits = 13;
+  class ContextIndexBits : public BitField<int, 0, kContextIndexBits> {};
+  class SlotIndexBits
+      : public BitField<int, kContextIndexBits, kSlotIndexBits> {};
+
+  virtual Code::Kind kind() const { return Code::LOAD_IC; }
+  virtual Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
+
+
+  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+    return ContextOnlyDescriptor(isolate());
+  }
+
+  DEFINE_HANDLER_CODE_STUB(LoadGlobalContextField, HandlerStub);
+};
+
+
 class LoadFastElementStub : public HydrogenCodeStub {
  public:
   LoadFastElementStub(Isolate* isolate, bool is_js_array,
index 8182532039996035798764d6f4fb56f0fd5f8a5c..a859a0bf25e351340a77dad804e87a2e5b74e63b 100644 (file)
@@ -229,8 +229,14 @@ class GlobalContextTable : public FixedArray {
   static Handle<GlobalContextTable> Extend(Handle<GlobalContextTable> table,
                                            Handle<Context> global_context);
 
+  static int GetContextOffset(int context_index) {
+    return kFirstContextOffset + context_index * kPointerSize;
+  }
+
  private:
   static const int kUsedSlot = 0;
+  static const int kFirstContextOffset =
+      FixedArray::kHeaderSize + (kUsedSlot + 1) * kPointerSize;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(GlobalContextTable);
 };
index 1589066374be9d7f5337bd3200462b7aef2c291a..0ec438489cefb2fdc065bc374a2f149b8b8c1147 100644 (file)
@@ -4645,6 +4645,14 @@ HObjectAccess HObjectAccess::ForContextSlot(int index) {
 }
 
 
+HObjectAccess HObjectAccess::ForGlobalContext(int index) {
+  DCHECK(index >= 0);
+  Portion portion = kInobject;
+  int offset = GlobalContextTable::GetContextOffset(index);
+  return HObjectAccess(portion, offset, Representation::Tagged());
+}
+
+
 HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) {
   DCHECK(offset >= 0);
   Portion portion = kInobject;
index 1a634aff2c42bf582d1fa52a161ae7f78972e23d..8994a87edb5875b7bd3f7b018b3ff3bc94791750 100644 (file)
@@ -6276,6 +6276,8 @@ class HObjectAccess FINAL {
 
   static HObjectAccess ForContextSlot(int index);
 
+  static HObjectAccess ForGlobalContext(int index);
+
   // Create an access to the backing store of an object.
   static HObjectAccess ForBackingStoreOffset(int offset,
       Representation representation = Representation::Tagged());
index 3386e60cb08cfcedf1a0cc2f4f1cd07bfa0963a8..4b52f26a84e7aa75bd9886d9e6beef2efc7b579e 100644 (file)
@@ -5376,6 +5376,22 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
       }
 
       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, variable->name(),
+                                       &lookup)) {
+          Handle<Context> global_context = GlobalContextTable::GetContext(
+              global_contexts, lookup.context_index);
+          HInstruction* result = New<HLoadNamedField>(
+              Add<HConstant>(global_context), static_cast<HValue*>(NULL),
+              HObjectAccess::ForContextSlot(lookup.slot_index));
+          return ast_context()->ReturnInstruction(result, expr->id());
+        }
+      }
+
       LookupIterator it(global, variable->name(),
                         LookupIterator::OWN_SKIP_INTERCEPTOR);
       GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD);
index e83a4b217d4f0b53c1aa8f9f081f1e68a9570291..810a149936fc6226df794e8f2f3f42b7e0880be0 100644 (file)
@@ -670,6 +670,10 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
 
     GlobalContextTable::LookupResult lookup_result;
     if (GlobalContextTable::Lookup(global_contexts, str_name, &lookup_result)) {
+      if (use_ic && LoadGlobalContextFieldStub::Accepted(&lookup_result)) {
+        LoadGlobalContextFieldStub stub(isolate(), &lookup_result);
+        PatchCache(name, stub.GetCode());
+      }
       return FixedArray::get(GlobalContextTable::GetContext(
                                  global_contexts, lookup_result.context_index),
                              lookup_result.slot_index);
index 9ebaeeca2e64d1535b68a4af0a93b2c8de54a32c..ab5f192a08d6d861251ce83b217575ce9133b55a 100644 (file)
@@ -988,7 +988,7 @@ TEST(CrossScriptStaticLookupUndeclared) {
 
     context.Check(
         "function f(o) { return x; }"
-        "function g(o) { x = 15; }"
+        "function g(v) { x = v; }"
         "function h(o) { return typeof x; }",
         EXPECT_RESULT, Undefined(CcTest::isolate()));
     context.Check("h({})", EXPECT_RESULT, undefined_string);
@@ -999,10 +999,66 @@ TEST(CrossScriptStaticLookupUndeclared) {
         EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
     context.Check(
         "'use strict';"
-        "g({});x",
+        "g(15);x",
         EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
     context.Check("h({})", EXPECT_RESULT, number_string);
     context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
     context.Check("h({})", EXPECT_RESULT, number_string);
   }
 }
+
+
+TEST(CrossScriptICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "function g() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(g); g()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+}