Chromium Code Reviews| Index: src/ic.cc |
| diff --git a/src/ic.cc b/src/ic.cc |
| index f99fcf430efab50304b82ad23d974162eb1ec163..3dc16da1859c851a4688ad21e24178af3a0b09d4 100644 |
| --- a/src/ic.cc |
| +++ b/src/ic.cc |
| @@ -371,8 +371,6 @@ static bool HasInterceptorGetter(JSObject* object) { |
| static void LookupForRead(Object* object, |
| String* name, |
| LookupResult* lookup) { |
| - AssertNoAllocation no_gc; // pointers must stay valid |
|
Kevin Millikin (Chromium)
2011/10/18 08:46:47
Can we restore this assert scope in the raw pointe
ulan
2011/10/18 09:31:00
Done.
|
| - |
| // Skip all the objects with named interceptors, but |
| // without actual getter. |
| while (true) { |
| @@ -408,6 +406,44 @@ static void LookupForRead(Object* object, |
| } |
| +static void LookupForRead(Handle<Object> object, |
| + Handle<String> name, |
| + LookupResult* lookup) { |
| + // Skip all the objects with named interceptors, but |
| + // without actual getter. |
| + while (true) { |
| + object->Lookup(*name, lookup); |
| + // Besides normal conditions (property not found or it's not |
| + // an interceptor), bail out if lookup is not cacheable: we won't |
| + // be able to IC it anyway and regular lookup should work fine. |
| + if (!lookup->IsFound() |
| + || (lookup->type() != INTERCEPTOR) |
| + || !lookup->IsCacheable()) { |
| + return; |
| + } |
| + |
| + Handle<JSObject> holder(lookup->holder()); |
| + if (HasInterceptorGetter(*holder)) { |
| + return; |
| + } |
| + |
| + holder->LocalLookupRealNamedProperty(*name, lookup); |
| + if (lookup->IsProperty()) { |
| + ASSERT(lookup->type() != INTERCEPTOR); |
| + return; |
| + } |
| + |
| + Handle<Object> proto(holder->GetPrototype()); |
| + if (proto->IsNull()) { |
| + lookup->NotFound(); |
| + return; |
| + } |
| + |
| + object = proto; |
| + } |
| +} |
| + |
| + |
| Object* CallICBase::TryCallAsFunction(Object* object) { |
| HandleScope scope(isolate()); |
| Handle<Object> target(object, isolate()); |
| @@ -850,53 +886,44 @@ MaybeObject* LoadIC::Load(State state, |
| // the underlying string value. See ECMA-262 15.5.5.1. |
| if ((object->IsString() || object->IsStringWrapper()) && |
| name->Equals(isolate()->heap()->length_symbol())) { |
| - AssertNoAllocation no_allocation; |
| - Code* stub = NULL; |
| + Handle<Code> stub; |
| if (state == UNINITIALIZED) { |
| stub = pre_monomorphic_stub(); |
| } else if (state == PREMONOMORPHIC) { |
| - if (object->IsString()) { |
| - stub = isolate()->builtins()->builtin( |
| - Builtins::kLoadIC_StringLength); |
| - } else { |
| - stub = isolate()->builtins()->builtin( |
| - Builtins::kLoadIC_StringWrapperLength); |
| - } |
| + stub = object->IsString() |
| + ? isolate()->builtins()->LoadIC_StringLength() |
| + : isolate()->builtins()->LoadIC_StringWrapperLength(); |
| } else if (state == MONOMORPHIC && object->IsStringWrapper()) { |
| - stub = isolate()->builtins()->builtin( |
| - Builtins::kLoadIC_StringWrapperLength); |
| + stub = isolate()->builtins()->LoadIC_StringWrapperLength(); |
| } else if (state != MEGAMORPHIC) { |
| stub = megamorphic_stub(); |
| } |
| - if (stub != NULL) { |
| - set_target(stub); |
| + if (!stub.is_null()) { |
| + set_target(*stub); |
| #ifdef DEBUG |
| if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); |
| #endif |
| } |
| // Get the string if we have a string wrapper object. |
| - if (object->IsJSValue()) { |
| - return Smi::FromInt( |
| - String::cast(Handle<JSValue>::cast(object)->value())->length()); |
| - } |
| - return Smi::FromInt(String::cast(*object)->length()); |
| + Handle<Object> string = object->IsJSValue() |
| + ? Handle<Object>(Handle<JSValue>::cast(object)->value()) |
| + : object; |
| + return Smi::FromInt(String::cast(*string)->length()); |
| } |
| // Use specialized code for getting the length of arrays. |
| if (object->IsJSArray() && |
| name->Equals(isolate()->heap()->length_symbol())) { |
| - AssertNoAllocation no_allocation; |
| - Code* stub = NULL; |
| + Handle<Code> stub; |
| if (state == UNINITIALIZED) { |
| stub = pre_monomorphic_stub(); |
| } else if (state == PREMONOMORPHIC) { |
| - stub = isolate()->builtins()->builtin( |
| - Builtins::kLoadIC_ArrayLength); |
| + stub = isolate()->builtins()->LoadIC_ArrayLength(); |
| } else if (state != MEGAMORPHIC) { |
| stub = megamorphic_stub(); |
| } |
| - if (stub != NULL) { |
| - set_target(stub); |
| + if (!stub.is_null()) { |
| + set_target(*stub); |
| #ifdef DEBUG |
| if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); |
| #endif |
| @@ -907,24 +934,21 @@ MaybeObject* LoadIC::Load(State state, |
| // Use specialized code for getting prototype of functions. |
| if (object->IsJSFunction() && |
| name->Equals(isolate()->heap()->prototype_symbol()) && |
| - JSFunction::cast(*object)->should_have_prototype()) { |
| - { AssertNoAllocation no_allocation; |
| - Code* stub = NULL; |
| + Handle<JSFunction>::cast(object)->should_have_prototype()) { |
| + Handle<Code> stub; |
|
Kevin Millikin (Chromium)
2011/10/18 08:46:47
Indentation of the body is wrong (too far to the r
ulan
2011/10/18 09:31:00
Done.
|
| if (state == UNINITIALIZED) { |
| stub = pre_monomorphic_stub(); |
| } else if (state == PREMONOMORPHIC) { |
| - stub = isolate()->builtins()->builtin( |
| - Builtins::kLoadIC_FunctionPrototype); |
| + stub = isolate()->builtins()->LoadIC_FunctionPrototype(); |
| } else if (state != MEGAMORPHIC) { |
| stub = megamorphic_stub(); |
| } |
| - if (stub != NULL) { |
| - set_target(stub); |
| + if (!stub.is_null()) { |
| + set_target(*stub); |
| #ifdef DEBUG |
| if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); |
| #endif |
| } |
| - } |
| return Accessors::FunctionGetPrototype(*object, 0); |
| } |
| } |
| @@ -936,7 +960,7 @@ MaybeObject* LoadIC::Load(State state, |
| // Named lookup in the object. |
| LookupResult lookup; |
| - LookupForRead(*object, *name, &lookup); |
| + LookupForRead(object, name, &lookup); |
| // If we did not find a property, check if we need to throw an exception. |
| if (!lookup.IsProperty()) { |
| @@ -955,17 +979,15 @@ MaybeObject* LoadIC::Load(State state, |
| if (lookup.IsProperty() && |
| (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) { |
| // Get the property. |
| - Object* result; |
| - { MaybeObject* maybe_result = |
| - object->GetProperty(*object, &lookup, *name, &attr); |
| - if (!maybe_result->ToObject(&result)) return maybe_result; |
| - } |
| + Handle<Object> result = |
| + Object::GetProperty(isolate(), object, object, &lookup, name, &attr); |
| + RETURN_IF_EMPTY_HANDLE(isolate(), result); |
| // If the property is not present, check if we need to throw an |
| // exception. |
| if (attr == ABSENT && IsContextual(object)) { |
| return ReferenceError("not_defined", name); |
| } |
| - return result; |
| + return *result; |
| } |
| // Get the property. |
| @@ -988,91 +1010,75 @@ void LoadIC::UpdateCaches(LookupResult* lookup, |
| if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
| // Compute the code stub for this load. |
| - MaybeObject* maybe_code = NULL; |
| - Object* code; |
| + Handle<Code> code; |
| if (state == UNINITIALIZED) { |
| // This is the first time we execute this inline cache. |
| // Set the target to the pre monomorphic stub to delay |
| // setting the monomorphic state. |
| - maybe_code = pre_monomorphic_stub(); |
| + code = pre_monomorphic_stub(); |
| } else if (!lookup->IsProperty()) { |
| // Nonexistent property. The result is undefined. |
| - maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name, |
| - *receiver); |
| + code = isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); |
| } else { |
| // Compute monomorphic stub. |
| + Handle<JSObject> holder(lookup->holder()); |
| switch (lookup->type()) { |
| - case FIELD: { |
| - maybe_code = isolate()->stub_cache()->ComputeLoadField( |
| - *name, |
| - *receiver, |
| - lookup->holder(), |
| - lookup->GetFieldIndex()); |
| + case FIELD: |
| + code = isolate()->stub_cache()->ComputeLoadField( |
| + name, receiver, holder, lookup->GetFieldIndex()); |
| break; |
| - } |
| case CONSTANT_FUNCTION: { |
| - Object* constant = lookup->GetConstantFunction(); |
| - maybe_code = isolate()->stub_cache()->ComputeLoadConstant( |
| - *name, *receiver, lookup->holder(), constant); |
| + Handle<Object> constant(lookup->GetConstantFunction()); |
| + code = isolate()->stub_cache()->ComputeLoadConstant( |
| + name, receiver, holder, constant); |
| break; |
| } |
| - case NORMAL: { |
| - if (lookup->holder()->IsGlobalObject()) { |
| - GlobalObject* global = GlobalObject::cast(lookup->holder()); |
| - JSGlobalPropertyCell* cell = |
| - JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| - maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name, |
| - *receiver, |
| - global, |
| - cell, |
| - lookup->IsDontDelete()); |
| + case NORMAL: |
| + if (holder->IsGlobalObject()) { |
| + Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| + Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
| + code = isolate()->stub_cache()->ComputeLoadGlobal( |
| + name, receiver, global, cell, lookup->IsDontDelete()); |
| } else { |
| // There is only one shared stub for loading normalized |
| // properties. It does not traverse the prototype chain, so the |
| // property must be found in the receiver for the stub to be |
| // applicable. |
| - if (lookup->holder() != *receiver) return; |
| - maybe_code = isolate()->stub_cache()->ComputeLoadNormal(); |
| + if (!holder.is_identical_to(receiver)) return; |
| + code = isolate()->stub_cache()->ComputeLoadNormal(); |
| } |
| break; |
| - } |
| case CALLBACKS: { |
| - if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
| - AccessorInfo* callback = |
| - AccessorInfo::cast(lookup->GetCallbackObject()); |
| + Handle<Object> callback_object(lookup->GetCallbackObject()); |
| + if (!callback_object->IsAccessorInfo()) return; |
| + Handle<AccessorInfo> callback(AccessorInfo::cast(*callback_object)); |
| if (v8::ToCData<Address>(callback->getter()) == 0) return; |
| - maybe_code = isolate()->stub_cache()->ComputeLoadCallback( |
| - *name, *receiver, lookup->holder(), callback); |
| + code = isolate()->stub_cache()->ComputeLoadCallback( |
| + name, receiver, holder, callback); |
| break; |
| } |
| - case INTERCEPTOR: { |
| - ASSERT(HasInterceptorGetter(lookup->holder())); |
| - maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor( |
| - *name, *receiver, lookup->holder()); |
| + case INTERCEPTOR: |
| + ASSERT(HasInterceptorGetter(*holder)); |
| + code = isolate()->stub_cache()->ComputeLoadInterceptor( |
| + name, receiver, holder); |
| break; |
| - } |
| default: |
| return; |
| } |
| } |
| - // If we're unable to compute the stub (not enough memory left), we |
| - // simply avoid updating the caches. |
| - if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| - |
| // Patch the call site depending on the state of the cache. |
| - if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
| + if (state == UNINITIALIZED || |
| + state == PREMONOMORPHIC || |
| state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| - set_target(Code::cast(code)); |
| + set_target(*code); |
| } else if (state == MONOMORPHIC) { |
| - set_target(megamorphic_stub()); |
| + set_target(*megamorphic_stub()); |
| } else if (state == MEGAMORPHIC) { |
| // Cache code holding map should be consistent with |
| // GenerateMonomorphicCacheProbe. |
| - Map* map = JSObject::cast(object->IsJSObject() ? *object : |
| - object->GetPrototype())->map(); |
| - |
| - isolate()->stub_cache()->Set(*name, map, Code::cast(code)); |
| + Handle<Map> map(receiver->map()); |
| + isolate()->stub_cache()->Set(*name, *map, *code); |
|
Kevin Millikin (Chromium)
2011/10/18 08:46:47
I guess it doesn't make much sense to create a han
ulan
2011/10/18 09:31:00
Done.
|
| } |
| #ifdef DEBUG |
| @@ -1101,7 +1107,8 @@ MaybeObject* KeyedLoadIC::ComputePolymorphicStub( |
| handler_ics.Add(cached_stub); |
| } |
| Object* object; |
| - KeyedLoadStubCompiler compiler; |
| + HandleScope scope(isolate()); |
| + KeyedLoadStubCompiler compiler(isolate()); |
| MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps, |
| &handler_ics); |
| if (!maybe_code->ToObject(&object)) return maybe_code; |
| @@ -1808,7 +1815,8 @@ MaybeObject* KeyedStoreIC::ComputePolymorphicStub( |
| transitioned_maps.Add(transitioned_map); |
| } |
| Object* object; |
| - KeyedStoreStubCompiler compiler(strict_mode); |
| + HandleScope scope(isolate()); |
| + KeyedStoreStubCompiler compiler(isolate(), strict_mode); |
| MaybeObject* maybe_code = compiler.CompileStorePolymorphic( |
| receiver_maps, &handler_ics, &transitioned_maps); |
| if (!maybe_code->ToObject(&object)) return maybe_code; |
| @@ -2052,7 +2060,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { |
| // Used from ic-<arch>.cc. |
| RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { |
| - NoHandleAllocation na; |
| + HandleScope scope(isolate); |
| ASSERT(args.length() == 2); |
| LoadIC ic(isolate); |
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |