| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 9a56f23bd76d81417d9bfb41838e794e9209941f..947509c24e8965ff2f23826a0ccf744f5a7bfc86 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -371,8 +371,7 @@ static bool HasInterceptorGetter(JSObject* object) {
|
| static void LookupForRead(Object* object,
|
| String* name,
|
| LookupResult* lookup) {
|
| - AssertNoAllocation no_gc; // pointers must stay valid
|
| -
|
| + AssertNoAllocation no_gc;
|
| // Skip all the objects with named interceptors, but
|
| // without actual getter.
|
| while (true) {
|
| @@ -408,6 +407,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 +887,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,23 +935,20 @@ 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;
|
| - if (state == UNINITIALIZED) {
|
| - stub = pre_monomorphic_stub();
|
| - } else if (state == PREMONOMORPHIC) {
|
| - stub = isolate()->builtins()->builtin(
|
| - Builtins::kLoadIC_FunctionPrototype);
|
| - } else if (state != MEGAMORPHIC) {
|
| - stub = megamorphic_stub();
|
| - }
|
| - if (stub != NULL) {
|
| - set_target(stub);
|
| + Handle<JSFunction>::cast(object)->should_have_prototype()) {
|
| + Handle<Code> stub;
|
| + if (state == UNINITIALIZED) {
|
| + stub = pre_monomorphic_stub();
|
| + } else if (state == PREMONOMORPHIC) {
|
| + stub = isolate()->builtins()->LoadIC_FunctionPrototype();
|
| + } else if (state != MEGAMORPHIC) {
|
| + stub = megamorphic_stub();
|
| + }
|
| + if (!stub.is_null()) {
|
| + set_target(*stub);
|
| #ifdef DEBUG
|
| - if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
|
| + if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
|
| #endif
|
| - }
|
| }
|
| return Accessors::FunctionGetPrototype(*object, 0);
|
| }
|
| @@ -936,7 +961,7 @@ MaybeObject* LoadIC::Load(State state,
|
|
|
| // Named lookup in the object.
|
| LookupResult lookup(isolate());
|
| - 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 +980,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 +1011,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 =
|
| + Handle<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));
|
| + isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| }
|
|
|
| #ifdef DEBUG
|
| @@ -1101,7 +1108,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 +1816,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 +2061,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]);
|
|
|