Commit 62a94977 authored by antonm@chromium.org's avatar antonm@chromium.org

Compile very thin code to access objects on which indexed interceptor is set.

Review URL: http://codereview.chromium.org/603028

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3847 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f937e7da
......@@ -635,6 +635,11 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
}
void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
GenerateGeneric(masm);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- r0 : value
......
......@@ -705,6 +705,10 @@ static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
KeyedLoadIC::GeneratePreMonomorphic(masm);
}
static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
KeyedLoadIC::GenerateIndexedInterceptor(masm);
}
static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
StoreIC::GenerateInitialize(masm);
......
......@@ -89,6 +89,7 @@ enum BuiltinExtraArguments {
V(KeyedLoadIC_ExternalIntArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalUnsignedIntArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_ExternalFloatArray, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC) \
\
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
......
......@@ -586,6 +586,52 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
}
void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
// -- esp[0] : return address
// -- esp[4] : key
// -- esp[8] : receiver
// -----------------------------------
Label slow;
// Load key and receiver.
__ mov(eax, Operand(esp, kPointerSize));
__ mov(ecx, Operand(esp, 2 * kPointerSize));
// Check that the receiver isn't a smi.
__ test(ecx, Immediate(kSmiTagMask));
__ j(zero, &slow, not_taken);
// Check that the key is a smi.
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &slow, not_taken);
// Get the map of the receiver.
__ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
// Check that it has indexed interceptor and access checks
// are not enabled for this object.
__ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
__ and_(Operand(edx), Immediate(kSlowCaseBitFieldMask));
__ cmp(Operand(edx), Immediate(1 << Map::kHasIndexedInterceptor));
__ j(not_zero, &slow, not_taken);
// Everything is fine, call runtime.
__ pop(edx);
__ push(ecx); // receiver
__ push(eax); // key
__ push(edx); // return address
// Perform tail call to the entry.
__ TailCallRuntime(ExternalReference(
IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
__ bind(&slow);
GenerateMiss(masm);
}
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
......
......@@ -896,6 +896,8 @@ Object* KeyedLoadIC::Load(State state,
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (receiver->HasExternalArrayElements()) {
stub = external_array_stub(receiver->GetElementsKind());
} else if (receiver->HasIndexedInterceptor()) {
stub = indexed_interceptor_stub();
}
}
set_target(stub);
......
......@@ -53,6 +53,7 @@ enum DictionaryCheck { CHECK_DICTIONARY, DICTIONARY_CHECK_DONE };
ICU(LoadPropertyWithInterceptorOnly) \
ICU(LoadPropertyWithInterceptorForLoad) \
ICU(LoadPropertyWithInterceptorForCall) \
ICU(KeyedLoadPropertyWithInterceptor) \
ICU(StoreInterceptorProperty)
//
......@@ -293,6 +294,7 @@ class KeyedLoadIC: public IC {
// for all other types.
static void GenerateExternalArray(MacroAssembler* masm,
ExternalArrayType array_type);
static void GenerateIndexedInterceptor(MacroAssembler* masm);
// Clear the use of the inlined version.
static void ClearInlinedVersion(Address address);
......@@ -329,6 +331,10 @@ class KeyedLoadIC: public IC {
}
static Code* external_array_stub(JSObject::ElementsKind elements_kind);
static Code* indexed_interceptor_stub() {
return Builtins::builtin(Builtins::KeyedLoadIC_IndexedInterceptor);
}
static void Clear(Address address, Code* target);
// Support for patching the map that is checked in an inlined
......
......@@ -920,6 +920,13 @@ Object* StoreInterceptorProperty(Arguments args) {
}
Object* KeyedLoadPropertyWithInterceptor(Arguments args) {
JSObject* receiver = JSObject::cast(args[0]);
uint32_t index = Smi::cast(args[1])->value();
return receiver->GetElementWithInterceptor(receiver, index);
}
Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
HandleScope scope;
int argc = Code::ExtractArgumentsCountFromFlags(flags);
......
......@@ -312,6 +312,7 @@ Object* LoadPropertyWithInterceptorForLoad(Arguments args);
Object* LoadPropertyWithInterceptorForCall(Arguments args);
Object* StoreInterceptorProperty(Arguments args);
Object* CallInterceptorProperty(Arguments args);
Object* KeyedLoadPropertyWithInterceptor(Arguments args);
// Support function for computing call IC miss stubs.
......
......@@ -573,6 +573,11 @@ void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
}
void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
GenerateGeneric(masm);
}
void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : value
......
......@@ -2529,6 +2529,195 @@ THREADED_TEST(IndexedInterceptorWithNoSetter) {
}
THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
obj->TurnOnAccessCheck();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"try {"
" for (var i = 0; i < 100; i++) {"
" var v = obj[0];"
" if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"try {"
" for (var i = 0; i < 100; i++) {"
" var expected = i;"
" if (i == 5) {"
" %EnableAccessChecks(obj);"
" expected = undefined;"
" }"
" var v = obj[i];"
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
" if (i == 5) %DisableAccessChecks(obj);"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"try {"
" for (var i = 0; i < 100; i++) {"
" var v = obj[i];"
" if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"try {"
" for (var i = 0; i < 100; i++) {"
" var expected = i;"
" if (i == 50) {"
" i = 'foobar';"
" expected = undefined;"
" }"
" var v = obj[i];"
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"var original = obj;"
"try {"
" for (var i = 0; i < 100; i++) {"
" var expected = i;"
" if (i == 50) {"
" obj = {50: 'foobar'};"
" expected = 'foobar';"
" }"
" var v = obj[i];"
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
" if (i == 50) obj = original;"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"var original = obj;"
"try {"
" for (var i = 0; i < 100; i++) {"
" var expected = i;"
" if (i == 5) {"
" obj = 239;"
" expected = undefined;"
" }"
" var v = obj[i];"
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
" if (i == 5) obj = original;"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(IndexedInterceptorOnProto) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
LocalContext context;
Local<v8::Object> obj = templ->NewInstance();
context->Global()->Set(v8_str("obj"), obj);
const char* code =
"var o = {__proto__: obj};"
"try {"
" for (var i = 0; i < 100; i++) {"
" var v = o[i];"
" if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
" }"
" 'PASSED'"
"} catch(e) {"
" e"
"}";
ExpectString(code, "PASSED");
}
THREADED_TEST(MultiContexts) {
v8::HandleScope scope;
v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment