}
+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(
V(InternalArrayNoArgumentConstructor) \
V(InternalArraySingleArgumentConstructor) \
V(KeyedLoadGeneric) \
+ V(LoadGlobalContextField) \
V(LoadDictionaryElement) \
V(LoadFastElement) \
V(MegamorphicLoad) \
};
+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,
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);
};
}
+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;
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());
}
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);
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);
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);
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));
+ }
+}