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));
}
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),
V(NumberToString) \
V(RegExpConstructResult) \
V(StoreFastElement) \
+ V(StoreGlobalContextField) \
V(StringAdd) \
V(ToBoolean) \
V(TransitionElementsKind) \
};
-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) |
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);
};
}
+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>(
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) {
HInstruction* BuildGetNativeContext(HValue* closure);
HInstruction* BuildGetNativeContext();
+ HInstruction* BuildGetGlobalContext(int context_index);
HInstruction* BuildGetArrayFunction();
protected:
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;
}
}
-TEST(CrossScriptICs) {
+TEST(CrossScriptLoadICs) {
i::FLAG_harmony_scoping = true;
i::FLAG_allow_natives_syntax = true;
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));
+ }
+}