| Index: src/ic.cc
|
| ===================================================================
|
| --- src/ic.cc (revision 9808)
|
| +++ src/ic.cc (working copy)
|
| @@ -100,9 +100,13 @@
|
| PrintF("]\n");
|
| }
|
| }
|
| -#endif
|
| +#endif // DEBUG
|
|
|
|
|
| +#define TRACE_IC(type, name, old_state, new_target) \
|
| + ASSERT((TraceIC(type, name, old_state, new_target), true))
|
| +
|
| +
|
| IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
|
| ASSERT(isolate == Isolate::Current());
|
| // To improve the performance of the (much used) IC code, we unfold
|
| @@ -368,15 +372,13 @@
|
| }
|
|
|
|
|
| -static void LookupForRead(Object* object,
|
| - String* name,
|
| +static void LookupForRead(Handle<Object> object,
|
| + Handle<String> name,
|
| LookupResult* lookup) {
|
| - AssertNoAllocation no_gc; // pointers must stay valid
|
| -
|
| // Skip all the objects with named interceptors, but
|
| // without actual getter.
|
| while (true) {
|
| - object->Lookup(name, lookup);
|
| + 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.
|
| @@ -386,18 +388,18 @@
|
| return;
|
| }
|
|
|
| - JSObject* holder = lookup->holder();
|
| - if (HasInterceptorGetter(holder)) {
|
| + Handle<JSObject> holder(lookup->holder());
|
| + if (HasInterceptorGetter(*holder)) {
|
| return;
|
| }
|
|
|
| - holder->LocalLookupRealNamedProperty(name, lookup);
|
| + holder->LocalLookupRealNamedProperty(*name, lookup);
|
| if (lookup->IsProperty()) {
|
| ASSERT(lookup->type() != INTERCEPTOR);
|
| return;
|
| }
|
|
|
| - Object* proto = holder->GetPrototype();
|
| + Handle<Object> proto(holder->GetPrototype());
|
| if (proto->IsNull()) {
|
| lookup->NotFound();
|
| return;
|
| @@ -408,28 +410,29 @@
|
| }
|
|
|
|
|
| -Object* CallICBase::TryCallAsFunction(Object* object) {
|
| - HandleScope scope(isolate());
|
| - Handle<Object> target(object, isolate());
|
| - Handle<Object> delegate = Execution::GetFunctionDelegate(target);
|
| +Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
|
| + Handle<Object> delegate = Execution::GetFunctionDelegate(object);
|
|
|
| - if (delegate->IsJSFunction()) {
|
| + if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
|
| // Patch the receiver and use the delegate as the function to
|
| - // invoke. This is used for invoking objects as if they were
|
| - // functions.
|
| - const int argc = this->target()->arguments_count();
|
| + // invoke. This is used for invoking objects as if they were functions.
|
| + const int argc = target()->arguments_count();
|
| StackFrameLocator locator;
|
| JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
|
| int index = frame->ComputeExpressionsCount() - (argc + 1);
|
| - frame->SetExpression(index, *target);
|
| + frame->SetExpression(index, *object);
|
| }
|
|
|
| - return *delegate;
|
| + return delegate;
|
| }
|
|
|
|
|
| void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
|
| Handle<Object> object) {
|
| + while (callee->IsJSFunctionProxy()) {
|
| + callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap());
|
| + }
|
| +
|
| if (callee->IsJSFunction()) {
|
| Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
|
| if (function->shared()->strict_mode() || function->IsBuiltin()) {
|
| @@ -464,31 +467,27 @@
|
| // the element if so.
|
| uint32_t index;
|
| if (name->AsArrayIndex(&index)) {
|
| - Object* result;
|
| - { MaybeObject* maybe_result = object->GetElement(index);
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| - }
|
| + Handle<Object> result = Object::GetElement(object, index);
|
| + RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| + if (result->IsJSFunction()) return *result;
|
|
|
| - if (result->IsJSFunction()) return result;
|
| -
|
| // Try to find a suitable function delegate for the object at hand.
|
| result = TryCallAsFunction(result);
|
| - if (result->IsJSFunction()) return result;
|
| + if (result->IsJSFunction()) return *result;
|
|
|
| // Otherwise, it will fail in the lookup step.
|
| }
|
|
|
| // Lookup the property in the object.
|
| - LookupResult lookup;
|
| - LookupForRead(*object, *name, &lookup);
|
| + LookupResult lookup(isolate());
|
| + LookupForRead(object, name, &lookup);
|
|
|
| if (!lookup.IsProperty()) {
|
| // If the object does not have the requested property, check which
|
| // exception we need to throw.
|
| - if (IsContextual(object)) {
|
| - return ReferenceError("not_defined", name);
|
| - }
|
| - return TypeError("undefined_method", object, name);
|
| + return IsContextual(object)
|
| + ? ReferenceError("not_defined", name)
|
| + : TypeError("undefined_method", object, name);
|
| }
|
|
|
| // Lookup is valid: Update inline cache and stub cache.
|
| @@ -498,53 +497,42 @@
|
|
|
| // Get the property.
|
| PropertyAttributes attr;
|
| - Object* result;
|
| - { MaybeObject* maybe_result =
|
| - object->GetProperty(*object, &lookup, *name, &attr);
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| - }
|
| + Handle<Object> result =
|
| + Object::GetProperty(object, object, &lookup, name, &attr);
|
| + RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
|
|
| - if (lookup.type() == INTERCEPTOR) {
|
| + if (lookup.type() == INTERCEPTOR && attr == ABSENT) {
|
| // If the object does not have the requested property, check which
|
| // exception we need to throw.
|
| - if (attr == ABSENT) {
|
| - if (IsContextual(object)) {
|
| - return ReferenceError("not_defined", name);
|
| - }
|
| - return TypeError("undefined_method", object, name);
|
| - }
|
| + return IsContextual(object)
|
| + ? ReferenceError("not_defined", name)
|
| + : TypeError("undefined_method", object, name);
|
| }
|
|
|
| ASSERT(!result->IsTheHole());
|
|
|
| - HandleScope scope(isolate());
|
| - // Wrap result in a handle because ReceiverToObjectIfRequired may allocate
|
| - // new object and cause GC.
|
| - Handle<Object> result_handle(result);
|
| // Make receiver an object if the callee requires it. Strict mode or builtin
|
| // functions do not wrap the receiver, non-strict functions and objects
|
| // called as functions do.
|
| - ReceiverToObjectIfRequired(result_handle, object);
|
| + ReceiverToObjectIfRequired(result, object);
|
|
|
| - if (result_handle->IsJSFunction()) {
|
| + if (result->IsJSFunction()) {
|
| + Handle<JSFunction> function = Handle<JSFunction>::cast(result);
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| // Handle stepping into a function if step into is active.
|
| Debug* debug = isolate()->debug();
|
| if (debug->StepInActive()) {
|
| // Protect the result in a handle as the debugger can allocate and might
|
| // cause GC.
|
| - Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
|
| debug->HandleStepIn(function, object, fp(), false);
|
| - return *function;
|
| }
|
| #endif
|
| -
|
| - return *result_handle;
|
| + return *function;
|
| }
|
|
|
| // Try to find a suitable function delegate for the object at hand.
|
| - result_handle = Handle<Object>(TryCallAsFunction(*result_handle));
|
| - if (result_handle->IsJSFunction()) return *result_handle;
|
| + result = TryCallAsFunction(result);
|
| + if (result->IsJSFunction()) return *result;
|
|
|
| return TypeError("property_not_function", object, name);
|
| }
|
| @@ -594,89 +582,57 @@
|
| }
|
|
|
|
|
| -MaybeObject* CallICBase::ComputeMonomorphicStub(
|
| - LookupResult* lookup,
|
| - State state,
|
| - Code::ExtraICState extra_ic_state,
|
| - Handle<Object> object,
|
| - Handle<String> name) {
|
| +Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
|
| + State state,
|
| + Code::ExtraICState extra_state,
|
| + Handle<Object> object,
|
| + Handle<String> name) {
|
| int argc = target()->arguments_count();
|
| - MaybeObject* maybe_code = NULL;
|
| + Handle<JSObject> holder(lookup->holder());
|
| switch (lookup->type()) {
|
| case FIELD: {
|
| int index = lookup->GetFieldIndex();
|
| - maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
|
| - kind_,
|
| - extra_ic_state,
|
| - *name,
|
| - *object,
|
| - lookup->holder(),
|
| - index);
|
| - break;
|
| + return isolate()->stub_cache()->ComputeCallField(
|
| + argc, kind_, extra_state, name, object, holder, index);
|
| }
|
| case CONSTANT_FUNCTION: {
|
| // Get the constant function and compute the code stub for this
|
| // call; used for rewriting to monomorphic state and making sure
|
| // that the code stub is in the stub cache.
|
| - JSFunction* function = lookup->GetConstantFunction();
|
| - maybe_code =
|
| - isolate()->stub_cache()->ComputeCallConstant(argc,
|
| - kind_,
|
| - extra_ic_state,
|
| - *name,
|
| - *object,
|
| - lookup->holder(),
|
| - function);
|
| - break;
|
| + Handle<JSFunction> function(lookup->GetConstantFunction());
|
| + return isolate()->stub_cache()->ComputeCallConstant(
|
| + argc, kind_, extra_state, name, object, holder, function);
|
| }
|
| case NORMAL: {
|
| - if (!object->IsJSObject()) return NULL;
|
| + // If we return a null handle, the IC will not be patched.
|
| + if (!object->IsJSObject()) return Handle<Code>::null();
|
| Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
|
|
| - if (lookup->holder()->IsGlobalObject()) {
|
| - GlobalObject* global = GlobalObject::cast(lookup->holder());
|
| - JSGlobalPropertyCell* cell =
|
| - JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
|
| - if (!cell->value()->IsJSFunction()) return NULL;
|
| - JSFunction* function = JSFunction::cast(cell->value());
|
| - maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
|
| - kind_,
|
| - extra_ic_state,
|
| - *name,
|
| - *receiver,
|
| - global,
|
| - cell,
|
| - function);
|
| + if (holder->IsGlobalObject()) {
|
| + Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
|
| + Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
|
| + if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
|
| + Handle<JSFunction> function(JSFunction::cast(cell->value()));
|
| + return isolate()->stub_cache()->ComputeCallGlobal(
|
| + argc, kind_, extra_state, name, receiver, global, cell, function);
|
| } else {
|
| // There is only one shared stub for calling 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 NULL;
|
| - maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
|
| - kind_,
|
| - extra_ic_state,
|
| - *name,
|
| - *receiver);
|
| + if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
|
| + return isolate()->stub_cache()->ComputeCallNormal(
|
| + argc, kind_, extra_state);
|
| }
|
| break;
|
| }
|
| - case INTERCEPTOR: {
|
| - ASSERT(HasInterceptorGetter(lookup->holder()));
|
| - maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
|
| - argc,
|
| - kind_,
|
| - extra_ic_state,
|
| - *name,
|
| - *object,
|
| - lookup->holder());
|
| - break;
|
| - }
|
| + case INTERCEPTOR:
|
| + ASSERT(HasInterceptorGetter(*holder));
|
| + return isolate()->stub_cache()->ComputeCallInterceptor(
|
| + argc, kind_, extra_state, name, object, holder);
|
| default:
|
| - maybe_code = NULL;
|
| - break;
|
| + return Handle<Code>::null();
|
| }
|
| - return maybe_code;
|
| }
|
|
|
|
|
| @@ -698,75 +654,57 @@
|
|
|
| // Compute the number of arguments.
|
| int argc = target()->arguments_count();
|
| - MaybeObject* maybe_code = NULL;
|
| bool had_proto_failure = false;
|
| + 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 =
|
| - isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
|
| - kind_,
|
| - extra_ic_state);
|
| + code = isolate()->stub_cache()->ComputeCallPreMonomorphic(
|
| + argc, kind_, extra_ic_state);
|
| } else if (state == MONOMORPHIC) {
|
| if (kind_ == Code::CALL_IC &&
|
| TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
|
| - maybe_code = ComputeMonomorphicStub(lookup,
|
| - state,
|
| - extra_ic_state,
|
| - object,
|
| - name);
|
| + code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
|
| + object, name);
|
| } else if (kind_ == Code::CALL_IC &&
|
| TryRemoveInvalidPrototypeDependentStub(target(),
|
| *object,
|
| *name)) {
|
| had_proto_failure = true;
|
| - maybe_code = ComputeMonomorphicStub(lookup,
|
| - state,
|
| - extra_ic_state,
|
| - object,
|
| - name);
|
| + code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
|
| + object, name);
|
| } else {
|
| - maybe_code =
|
| - isolate()->stub_cache()->ComputeCallMegamorphic(argc,
|
| - kind_,
|
| - extra_ic_state);
|
| + code = isolate()->stub_cache()->ComputeCallMegamorphic(
|
| + argc, kind_, extra_ic_state);
|
| }
|
| } else {
|
| - maybe_code = ComputeMonomorphicStub(lookup,
|
| - state,
|
| - extra_ic_state,
|
| - object,
|
| - name);
|
| + code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
|
| + object, name);
|
| }
|
|
|
| - // If we're unable to compute the stub (not enough memory left), we
|
| - // simply avoid updating the caches.
|
| - Object* code;
|
| - if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
|
| + // If there's no appropriate stub we simply avoid updating the caches.
|
| + if (code.is_null()) return;
|
|
|
| // Patch the call site depending on the state of the cache.
|
| if (state == UNINITIALIZED ||
|
| state == PREMONOMORPHIC ||
|
| state == MONOMORPHIC ||
|
| state == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
| - set_target(Code::cast(code));
|
| + set_target(*code);
|
| } else if (state == MEGAMORPHIC) {
|
| // Cache code holding map should be consistent with
|
| // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
|
| - Map* map = JSObject::cast(object->IsJSObject() ? *object :
|
| - object->GetPrototype())->map();
|
| -
|
| + Handle<JSObject> cache_object = object->IsJSObject()
|
| + ? Handle<JSObject>::cast(object)
|
| + : Handle<JSObject>(JSObject::cast(object->GetPrototype()));
|
| // Update the stub cache.
|
| - isolate()->stub_cache()->Set(*name, map, Code::cast(code));
|
| + isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
|
| }
|
|
|
| - USE(had_proto_failure);
|
| -#ifdef DEBUG
|
| if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
|
| - TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
|
| - name, state, target());
|
| -#endif
|
| + TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
|
| + name, state, target());
|
| }
|
|
|
|
|
| @@ -786,34 +724,22 @@
|
|
|
| if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
|
| int argc = target()->arguments_count();
|
| - Heap* heap = Handle<HeapObject>::cast(object)->GetHeap();
|
| - Map* map = heap->non_strict_arguments_elements_map();
|
| + Handle<Map> map =
|
| + isolate()->factory()->non_strict_arguments_elements_map();
|
| if (object->IsJSObject() &&
|
| - Handle<JSObject>::cast(object)->elements()->map() == map) {
|
| - MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
|
| + Handle<JSObject>::cast(object)->elements()->map() == *map) {
|
| + Handle<Code> code = isolate()->stub_cache()->ComputeCallArguments(
|
| argc, Code::KEYED_CALL_IC);
|
| - Object* code;
|
| - if (maybe_code->ToObject(&code)) {
|
| - set_target(Code::cast(code));
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedCallIC", key, state, target());
|
| -#endif
|
| - }
|
| - } else if (FLAG_use_ic && state != MEGAMORPHIC &&
|
| - !object->IsAccessCheckNeeded()) {
|
| - MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
|
| + set_target(*code);
|
| + TRACE_IC("KeyedCallIC", key, state, target());
|
| + } else if (!object->IsAccessCheckNeeded()) {
|
| + Handle<Code> code = isolate()->stub_cache()->ComputeCallMegamorphic(
|
| argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
|
| - Object* code;
|
| - if (maybe_code->ToObject(&code)) {
|
| - set_target(Code::cast(code));
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedCallIC", key, state, target());
|
| -#endif
|
| - }
|
| + set_target(*code);
|
| + TRACE_IC("KeyedCallIC", key, state, target());
|
| }
|
| }
|
|
|
| - HandleScope scope(isolate());
|
| Handle<Object> result = GetProperty(object, key);
|
| RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
|
|
| @@ -821,10 +747,10 @@
|
| // functions do not wrap the receiver, non-strict functions and objects
|
| // called as functions do.
|
| ReceiverToObjectIfRequired(result, object);
|
| + if (result->IsJSFunction()) return *result;
|
|
|
| + result = TryCallAsFunction(result);
|
| if (result->IsJSFunction()) return *result;
|
| - result = Handle<Object>(TryCallAsFunction(*result));
|
| - if (result->IsJSFunction()) return *result;
|
|
|
| return TypeError("property_not_function", object, key);
|
| }
|
| @@ -846,53 +772,44 @@
|
| // 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
|
| @@ -903,23 +820,20 @@
|
| // 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);
|
| }
|
| @@ -931,8 +845,8 @@
|
| if (name->AsArrayIndex(&index)) return object->GetElement(index);
|
|
|
| // Named lookup in the object.
|
| - LookupResult lookup;
|
| - LookupForRead(*object, *name, &lookup);
|
| + LookupResult lookup(isolate());
|
| + LookupForRead(object, name, &lookup);
|
|
|
| // If we did not find a property, check if we need to throw an exception.
|
| if (!lookup.IsProperty()) {
|
| @@ -951,17 +865,15 @@
|
| 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(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.
|
| @@ -984,128 +896,105 @@
|
| 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
|
| - TraceIC("LoadIC", name, state, target());
|
| -#endif
|
| + TRACE_IC("LoadIC", name, state, target());
|
| }
|
|
|
|
|
| -MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck(
|
| +Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck(
|
| bool is_js_array,
|
| ElementsKind elements_kind) {
|
| - return KeyedLoadElementStub(elements_kind).TryGetCode();
|
| + return KeyedLoadElementStub(elements_kind).GetCode();
|
| }
|
|
|
|
|
| -MaybeObject* KeyedLoadIC::ComputePolymorphicStub(
|
| - MapList* receiver_maps,
|
| +Handle<Code> KeyedLoadIC::ComputePolymorphicStub(
|
| + MapHandleList* receiver_maps,
|
| StrictModeFlag strict_mode) {
|
| - CodeList handler_ics(receiver_maps->length());
|
| + CodeHandleList handler_ics(receiver_maps->length());
|
| for (int i = 0; i < receiver_maps->length(); ++i) {
|
| - Map* receiver_map(receiver_maps->at(i));
|
| - MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
|
| + Handle<Map> receiver_map = receiver_maps->at(i);
|
| + Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck(
|
| receiver_map, strict_mode);
|
| - Code* cached_stub;
|
| - if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
|
| handler_ics.Add(cached_stub);
|
| }
|
| - Object* object;
|
| - KeyedLoadStubCompiler compiler;
|
| - MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps,
|
| - &handler_ics);
|
| - if (!maybe_code->ToObject(&object)) return maybe_code;
|
| + KeyedLoadStubCompiler compiler(isolate());
|
| + Handle<Code> code = compiler.CompileLoadPolymorphic(
|
| + receiver_maps, &handler_ics);
|
| isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
|
| - PROFILE(isolate(), CodeCreateEvent(
|
| - Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG,
|
| - Code::cast(object), 0));
|
| - return object;
|
| + PROFILE(isolate(),
|
| + CodeCreateEvent(Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, *code, 0));
|
| + return code;
|
| }
|
|
|
|
|
| @@ -1115,9 +1004,8 @@
|
| bool force_generic_stub) {
|
| // Check for values that can be converted into a symbol.
|
| // TODO(1295): Remove this code.
|
| - HandleScope scope(isolate());
|
| if (key->IsHeapNumber() &&
|
| - isnan(HeapNumber::cast(*key)->value())) {
|
| + isnan(Handle<HeapNumber>::cast(key)->value())) {
|
| key = isolate()->factory()->nan_symbol();
|
| } else if (key->IsUndefined()) {
|
| key = isolate()->factory()->undefined_symbol();
|
| @@ -1139,16 +1027,11 @@
|
| if (object->IsString() &&
|
| name->Equals(isolate()->heap()->length_symbol())) {
|
| Handle<String> string = Handle<String>::cast(object);
|
| - Object* code = NULL;
|
| - { MaybeObject* maybe_code =
|
| - isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
|
| - *string);
|
| - if (!maybe_code->ToObject(&code)) return maybe_code;
|
| - }
|
| - set_target(Code::cast(code));
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedLoadIC", name, state, target());
|
| -#endif // DEBUG
|
| + Handle<Code> code =
|
| + isolate()->stub_cache()->ComputeKeyedLoadStringLength(name, string);
|
| + ASSERT(!code.is_null());
|
| + set_target(*code);
|
| + TRACE_IC("KeyedLoadIC", name, state, target());
|
| return Smi::FromInt(string->length());
|
| }
|
|
|
| @@ -1156,34 +1039,25 @@
|
| if (object->IsJSArray() &&
|
| name->Equals(isolate()->heap()->length_symbol())) {
|
| Handle<JSArray> array = Handle<JSArray>::cast(object);
|
| - Object* code;
|
| - { MaybeObject* maybe_code =
|
| - isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name,
|
| - *array);
|
| - if (!maybe_code->ToObject(&code)) return maybe_code;
|
| - }
|
| - set_target(Code::cast(code));
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedLoadIC", name, state, target());
|
| -#endif // DEBUG
|
| - return JSArray::cast(*object)->length();
|
| + Handle<Code> code =
|
| + isolate()->stub_cache()->ComputeKeyedLoadArrayLength(name, array);
|
| + ASSERT(!code.is_null());
|
| + set_target(*code);
|
| + TRACE_IC("KeyedLoadIC", name, state, target());
|
| + return array->length();
|
| }
|
|
|
| // Use specialized code for getting prototype of functions.
|
| if (object->IsJSFunction() &&
|
| name->Equals(isolate()->heap()->prototype_symbol()) &&
|
| - JSFunction::cast(*object)->should_have_prototype()) {
|
| + Handle<JSFunction>::cast(object)->should_have_prototype()) {
|
| Handle<JSFunction> function = Handle<JSFunction>::cast(object);
|
| - Object* code;
|
| - { MaybeObject* maybe_code =
|
| - isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
|
| - *name, *function);
|
| - if (!maybe_code->ToObject(&code)) return maybe_code;
|
| - }
|
| - set_target(Code::cast(code));
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedLoadIC", name, state, target());
|
| -#endif // DEBUG
|
| + Handle<Code> code =
|
| + isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
|
| + name, function);
|
| + ASSERT(!code.is_null());
|
| + set_target(*code);
|
| + TRACE_IC("KeyedLoadIC", name, state, target());
|
| return Accessors::FunctionGetPrototype(*object, 0);
|
| }
|
| }
|
| @@ -1192,15 +1066,14 @@
|
| // the element or char if so.
|
| uint32_t index = 0;
|
| if (name->AsArrayIndex(&index)) {
|
| - HandleScope scope(isolate());
|
| // Rewrite to the generic keyed load stub.
|
| - if (FLAG_use_ic) set_target(generic_stub());
|
| + if (FLAG_use_ic) set_target(*generic_stub());
|
| return Runtime::GetElementOrCharAt(isolate(), object, index);
|
| }
|
|
|
| // Named lookup.
|
| - LookupResult lookup;
|
| - LookupForRead(*object, *name, &lookup);
|
| + LookupResult lookup(isolate());
|
| + LookupForRead(object, name, &lookup);
|
|
|
| // If we did not find a property, check if we need to throw an exception.
|
| if (!lookup.IsProperty() && IsContextual(object)) {
|
| @@ -1214,17 +1087,15 @@
|
| PropertyAttributes attr;
|
| if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
|
| // 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(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;
|
| }
|
|
|
| return object->GetProperty(*object, &lookup, *name, &attr);
|
| @@ -1235,44 +1106,38 @@
|
| bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
|
|
|
| if (use_ic) {
|
| - Code* stub = generic_stub();
|
| + Handle<Code> stub = generic_stub();
|
| if (!force_generic_stub) {
|
| if (object->IsString() && key->IsNumber()) {
|
| if (state == UNINITIALIZED) {
|
| stub = string_stub();
|
| }
|
| } else if (object->IsJSObject()) {
|
| - JSObject* receiver = JSObject::cast(*object);
|
| - Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
|
| - Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
|
| - if (elements_map == heap->non_strict_arguments_elements_map()) {
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| + if (receiver->elements()->map() ==
|
| + isolate()->heap()->non_strict_arguments_elements_map()) {
|
| stub = non_strict_arguments_stub();
|
| } else if (receiver->HasIndexedInterceptor()) {
|
| stub = indexed_interceptor_stub();
|
| - } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
|
| - MaybeObject* maybe_stub = ComputeStub(receiver,
|
| - LOAD,
|
| - kNonStrictMode,
|
| - stub);
|
| - stub = maybe_stub->IsFailure() ?
|
| - NULL : Code::cast(maybe_stub->ToObjectUnchecked());
|
| + } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
|
| + stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub);
|
| }
|
| }
|
| }
|
| - if (stub != NULL) set_target(stub);
|
| + if (!stub.is_null()) set_target(*stub);
|
| }
|
|
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedLoadIC", key, state, target());
|
| -#endif // DEBUG
|
| + TRACE_IC("KeyedLoadIC", key, state, target());
|
|
|
| // Get the property.
|
| return Runtime::GetObjectProperty(isolate(), object, key);
|
| }
|
|
|
|
|
| -void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
|
| - Handle<Object> object, Handle<String> name) {
|
| +void KeyedLoadIC::UpdateCaches(LookupResult* lookup,
|
| + State state,
|
| + Handle<Object> object,
|
| + Handle<String> name) {
|
| // Bail out if we didn't find a result.
|
| if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
|
|
|
| @@ -1282,68 +1147,60 @@
|
| 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 {
|
| // Compute a monomorphic stub.
|
| + Handle<JSObject> holder(lookup->holder());
|
| switch (lookup->type()) {
|
| - case FIELD: {
|
| - maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField(
|
| - *name, *receiver, lookup->holder(), lookup->GetFieldIndex());
|
| + case FIELD:
|
| + code = isolate()->stub_cache()->ComputeKeyedLoadField(
|
| + name, receiver, holder, lookup->GetFieldIndex());
|
| break;
|
| - }
|
| case CONSTANT_FUNCTION: {
|
| - Object* constant = lookup->GetConstantFunction();
|
| - maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
|
| - *name, *receiver, lookup->holder(), constant);
|
| + Handle<Object> constant(lookup->GetConstantFunction());
|
| + code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
|
| + name, receiver, holder, constant);
|
| 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()->ComputeKeyedLoadCallback(
|
| - *name, *receiver, lookup->holder(), callback);
|
| + code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
|
| + name, receiver, holder, callback);
|
| break;
|
| }
|
| - case INTERCEPTOR: {
|
| + case INTERCEPTOR:
|
| ASSERT(HasInterceptorGetter(lookup->holder()));
|
| - maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
|
| - *name, *receiver, lookup->holder());
|
| + code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
|
| + name, receiver, holder);
|
| break;
|
| - }
|
| - default: {
|
| + default:
|
| // Always rewrite to the generic case so that we do not
|
| // repeatedly try to rewrite.
|
| - maybe_code = generic_stub();
|
| + code = generic_stub();
|
| break;
|
| - }
|
| }
|
| }
|
|
|
| - // 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. Make
|
| // sure to always rewrite from monomorphic to megamorphic.
|
| ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
|
| if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
|
| - set_target(Code::cast(code));
|
| + set_target(*code);
|
| } else if (state == MONOMORPHIC) {
|
| - set_target(megamorphic_stub());
|
| + set_target(*megamorphic_stub());
|
| }
|
|
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedLoadIC", name, state, target());
|
| -#endif
|
| + TRACE_IC("KeyedLoadIC", name, state, target());
|
| }
|
|
|
|
|
| @@ -1359,17 +1216,17 @@
|
| }
|
|
|
|
|
| -static bool LookupForWrite(JSObject* receiver,
|
| - String* name,
|
| +static bool LookupForWrite(Handle<JSObject> receiver,
|
| + Handle<String> name,
|
| LookupResult* lookup) {
|
| - receiver->LocalLookup(name, lookup);
|
| + receiver->LocalLookup(*name, lookup);
|
| if (!StoreICableLookup(lookup)) {
|
| return false;
|
| }
|
|
|
| if (lookup->type() == INTERCEPTOR &&
|
| receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
|
| - receiver->LocalLookupRealNamedProperty(name, lookup);
|
| + receiver->LocalLookupRealNamedProperty(*name, lookup);
|
| return StoreICableLookup(lookup);
|
| }
|
|
|
| @@ -1401,6 +1258,7 @@
|
| return TypeError("strict_read_only_property", object, name);
|
| }
|
| // Ignore other stores where the receiver is not a JSObject.
|
| + // TODO(1475): Must check prototype chains of object wrappers.
|
| return *value;
|
| }
|
|
|
| @@ -1409,31 +1267,30 @@
|
| // Check if the given name is an array index.
|
| uint32_t index;
|
| if (name->AsArrayIndex(&index)) {
|
| - HandleScope scope(isolate());
|
| Handle<Object> result = SetElement(receiver, index, value, strict_mode);
|
| - if (result.is_null()) return Failure::Exception();
|
| + RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| return *value;
|
| }
|
|
|
| // Use specialized code for setting the length of arrays.
|
| if (receiver->IsJSArray()
|
| && name->Equals(isolate()->heap()->length_symbol())
|
| - && JSArray::cast(*receiver)->AllowsSetElementsLength()) {
|
| + && Handle<JSArray>::cast(receiver)->AllowsSetElementsLength()) {
|
| #ifdef DEBUG
|
| if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
|
| #endif
|
| - Builtins::Name target = (strict_mode == kStrictMode)
|
| - ? Builtins::kStoreIC_ArrayLength_Strict
|
| - : Builtins::kStoreIC_ArrayLength;
|
| - set_target(isolate()->builtins()->builtin(target));
|
| + Handle<Code> stub = (strict_mode == kStrictMode)
|
| + ? isolate()->builtins()->StoreIC_ArrayLength_Strict()
|
| + : isolate()->builtins()->StoreIC_ArrayLength();
|
| + set_target(*stub);
|
| return receiver->SetProperty(*name, *value, NONE, strict_mode);
|
| }
|
|
|
| // Lookup the property locally in the receiver.
|
| if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
|
| - LookupResult lookup;
|
| + LookupResult lookup(isolate());
|
|
|
| - if (LookupForWrite(*receiver, *name, &lookup)) {
|
| + if (LookupForWrite(receiver, name, &lookup)) {
|
| // Generate a stub for this store.
|
| UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
|
| } else {
|
| @@ -1450,16 +1307,15 @@
|
| }
|
|
|
| if (receiver->IsJSGlobalProxy()) {
|
| + // TODO(ulan): find out why we patch this site even with --no-use-ic
|
| // Generate a generic stub that goes to the runtime when we see a global
|
| // proxy as receiver.
|
| - Code* stub = (strict_mode == kStrictMode)
|
| + Handle<Code> stub = (strict_mode == kStrictMode)
|
| ? global_proxy_stub_strict()
|
| : global_proxy_stub();
|
| - if (target() != stub) {
|
| - set_target(stub);
|
| -#ifdef DEBUG
|
| - TraceIC("StoreIC", name, state, target());
|
| -#endif
|
| + if (target() != *stub) {
|
| + set_target(*stub);
|
| + TRACE_IC("StoreIC", name, state, target());
|
| }
|
| }
|
|
|
| @@ -1487,89 +1343,82 @@
|
| // Compute the code stub for this store; used for rewriting to
|
| // monomorphic state and making sure that the code stub is in the
|
| // stub cache.
|
| - MaybeObject* maybe_code = NULL;
|
| - Object* code = NULL;
|
| + Handle<Code> code;
|
| switch (type) {
|
| - case FIELD: {
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreField(
|
| - *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
|
| + case FIELD:
|
| + code = isolate()->stub_cache()->ComputeStoreField(name,
|
| + receiver,
|
| + lookup->GetFieldIndex(),
|
| + Handle<Map>::null(),
|
| + strict_mode);
|
| break;
|
| - }
|
| case MAP_TRANSITION: {
|
| if (lookup->GetAttributes() != NONE) return;
|
| - HandleScope scope(isolate());
|
| ASSERT(type == MAP_TRANSITION);
|
| Handle<Map> transition(lookup->GetTransitionMap());
|
| int index = transition->PropertyIndexFor(*name);
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreField(
|
| - *name, *receiver, index, *transition, strict_mode);
|
| + code = isolate()->stub_cache()->ComputeStoreField(
|
| + name, receiver, index, transition, strict_mode);
|
| break;
|
| }
|
| - case NORMAL: {
|
| + case NORMAL:
|
| if (receiver->IsGlobalObject()) {
|
| // The stub generated for the global object picks the value directly
|
| // from the property cell. So the property must be directly on the
|
| // global object.
|
| Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
| - JSGlobalPropertyCell* cell =
|
| - JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
|
| - *name, *global, cell, strict_mode);
|
| + Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
|
| + code = isolate()->stub_cache()->ComputeStoreGlobal(
|
| + name, global, cell, strict_mode);
|
| } else {
|
| if (lookup->holder() != *receiver) return;
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
|
| + code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
|
| }
|
| 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->setter()) == 0) return;
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
|
| - *name, *receiver, callback, strict_mode);
|
| + code = isolate()->stub_cache()->ComputeStoreCallback(
|
| + name, receiver, callback, strict_mode);
|
| break;
|
| }
|
| - case INTERCEPTOR: {
|
| + case INTERCEPTOR:
|
| ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
|
| - maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
|
| - *name, *receiver, strict_mode);
|
| + code = isolate()->stub_cache()->ComputeStoreInterceptor(
|
| + name, receiver, strict_mode);
|
| 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 == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
| - set_target(Code::cast(code));
|
| + set_target(*code);
|
| } else if (state == MONOMORPHIC) {
|
| // Only move to megamorphic if the target changes.
|
| - if (target() != Code::cast(code)) {
|
| + if (target() != *code) {
|
| set_target((strict_mode == kStrictMode)
|
| ? megamorphic_stub_strict()
|
| : megamorphic_stub());
|
| }
|
| } else if (state == MEGAMORPHIC) {
|
| // Update the stub cache.
|
| - isolate()->stub_cache()->Set(*name,
|
| - receiver->map(),
|
| - Code::cast(code));
|
| + isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| }
|
|
|
| -#ifdef DEBUG
|
| - TraceIC("StoreIC", name, state, target());
|
| -#endif
|
| + TRACE_IC("StoreIC", name, state, target());
|
| }
|
|
|
|
|
| -static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
|
| - Map* new_receiver_map) {
|
| +static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
|
| + Handle<Map> new_receiver_map) {
|
| + ASSERT(!new_receiver_map.is_null());
|
| for (int current = 0; current < receiver_maps->length(); ++current) {
|
| - if (receiver_maps->at(current) == new_receiver_map) {
|
| + if (!receiver_maps->at(current).is_null() &&
|
| + receiver_maps->at(current).is_identical_to(new_receiver_map)) {
|
| return false;
|
| }
|
| }
|
| @@ -1578,45 +1427,40 @@
|
| }
|
|
|
|
|
| -void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
|
| +void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub,
|
| + MapHandleList* result) {
|
| ASSERT(stub->is_inline_cache_stub());
|
| - if (stub == string_stub()) {
|
| - return result->Add(isolate()->heap()->string_map());
|
| + if (!string_stub().is_null() && stub.is_identical_to(string_stub())) {
|
| + return result->Add(isolate()->factory()->string_map());
|
| } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
|
| if (stub->ic_state() == MONOMORPHIC) {
|
| - result->Add(Map::cast(stub->FindFirstMap()));
|
| + result->Add(Handle<Map>(stub->FindFirstMap()));
|
| } else {
|
| ASSERT(stub->ic_state() == MEGAMORPHIC);
|
| AssertNoAllocation no_allocation;
|
| int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
| - for (RelocIterator it(stub, mask); !it.done(); it.next()) {
|
| + for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
|
| RelocInfo* info = it.rinfo();
|
| - Object* object = info->target_object();
|
| + Handle<Object> object(info->target_object());
|
| ASSERT(object->IsMap());
|
| - result->Add(Map::cast(object));
|
| + AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| -MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
|
| +Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver,
|
| StubKind stub_kind,
|
| StrictModeFlag strict_mode,
|
| - Code* generic_stub) {
|
| + Handle<Code> generic_stub) {
|
| State ic_state = target()->ic_state();
|
| if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) &&
|
| !IsTransitionStubKind(stub_kind)) {
|
| - Code* monomorphic_stub;
|
| - MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
|
| - stub_kind,
|
| - strict_mode,
|
| - generic_stub);
|
| - if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
|
| -
|
| - return monomorphic_stub;
|
| + return ComputeMonomorphicStub(
|
| + receiver, stub_kind, strict_mode, generic_stub);
|
| }
|
| - ASSERT(target() != generic_stub);
|
| + ASSERT(target() != *generic_stub);
|
|
|
| // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
|
| // via megamorphic stubs, since they don't have a map in their relocation info
|
| @@ -1627,18 +1471,17 @@
|
|
|
| // Determine the list of receiver maps that this call site has seen,
|
| // adding the map that was just encountered.
|
| - MapList target_receiver_maps;
|
| + MapHandleList target_receiver_maps;
|
| + Handle<Map> receiver_map(receiver->map());
|
| if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
|
| - target_receiver_maps.Add(receiver->map());
|
| + target_receiver_maps.Add(receiver_map);
|
| } else {
|
| - GetReceiverMapsForStub(target(), &target_receiver_maps);
|
| + GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
|
| }
|
| bool map_added =
|
| - AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map());
|
| + AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
|
| if (IsTransitionStubKind(stub_kind)) {
|
| - MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind);
|
| - Map* new_map = NULL;
|
| - if (!maybe_map->To(&new_map)) return maybe_map;
|
| + Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind);
|
| map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map);
|
| }
|
| if (!map_added) {
|
| @@ -1653,31 +1496,24 @@
|
| return generic_stub;
|
| }
|
|
|
| - PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
|
| - Code::Flags flags = Code::ComputeFlags(this->kind(),
|
| - MEGAMORPHIC,
|
| - strict_mode);
|
| - Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
|
| - // If there is a cached stub, use it.
|
| - if (!maybe_cached_stub->IsUndefined()) {
|
| - ASSERT(maybe_cached_stub->IsCode());
|
| - return Code::cast(maybe_cached_stub);
|
| - }
|
| - MaybeObject* maybe_stub =
|
| + Handle<PolymorphicCodeCache> cache =
|
| + isolate()->factory()->polymorphic_code_cache();
|
| + Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, strict_mode);
|
| + Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags);
|
| + if (probe->IsCode()) return Handle<Code>::cast(probe);
|
| +
|
| + Handle<Code> stub =
|
| ComputePolymorphicStub(&target_receiver_maps, strict_mode);
|
| - Code* stub;
|
| - if (!maybe_stub->To(&stub)) return maybe_stub;
|
| - MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
|
| - if (maybe_update->IsFailure()) return maybe_update;
|
| + PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub);
|
| return stub;
|
| }
|
|
|
|
|
| -MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
|
| - Map* receiver_map,
|
| +Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
|
| + Handle<Map> receiver_map,
|
| StrictModeFlag strict_mode) {
|
| if ((receiver_map->instance_type() & kNotStringTag) == 0) {
|
| - ASSERT(string_stub() != NULL);
|
| + ASSERT(!string_stub().is_null());
|
| return string_stub();
|
| } else {
|
| ASSERT(receiver_map->has_dictionary_elements() ||
|
| @@ -1692,137 +1528,78 @@
|
| }
|
|
|
|
|
| -MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
|
| +Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<JSObject> receiver,
|
| StubKind stub_kind,
|
| StrictModeFlag strict_mode,
|
| - Code* generic_stub) {
|
| - Code* result = NULL;
|
| + Handle<Code> generic_stub) {
|
| if (receiver->HasFastElements() ||
|
| receiver->HasFastSmiOnlyElements() ||
|
| receiver->HasExternalArrayElements() ||
|
| receiver->HasFastDoubleElements() ||
|
| receiver->HasDictionaryElements()) {
|
| - MaybeObject* maybe_stub =
|
| - isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
|
| - receiver, stub_kind, strict_mode);
|
| - if (!maybe_stub->To(&result)) return maybe_stub;
|
| + return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
|
| + receiver, stub_kind, strict_mode);
|
| } else {
|
| - result = generic_stub;
|
| + return generic_stub;
|
| }
|
| - return result;
|
| }
|
|
|
|
|
| -MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver,
|
| - StubKind stub_kind) {
|
| +Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver,
|
| + StubKind stub_kind) {
|
| switch (stub_kind) {
|
| case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT:
|
| case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT:
|
| - return receiver->GetElementsTransitionMap(FAST_ELEMENTS);
|
| + return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
|
| + break;
|
| case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE:
|
| - return receiver->GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS);
|
| + return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
|
| + break;
|
| default:
|
| UNREACHABLE();
|
| - return NULL;
|
| + return Handle<Map>::null();
|
| }
|
| }
|
|
|
|
|
| -MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
|
| +Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck(
|
| bool is_js_array,
|
| ElementsKind elements_kind) {
|
| - return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
|
| + return KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
|
| }
|
|
|
|
|
| -// If |map| is contained in |maps_list|, returns |map|; otherwise returns NULL.
|
| -Map* GetMapIfPresent(Map* map, MapList* maps_list) {
|
| - for (int i = 0; i < maps_list->length(); ++i) {
|
| - if (maps_list->at(i) == map) return map;
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -
|
| -// Returns the most generic transitioned map for |map| that's found in
|
| -// |maps_list|, or NULL if no transitioned map for |map| is found at all.
|
| -Map* GetTransitionedMap(Map* map, MapList* maps_list) {
|
| - ElementsKind elements_kind = map->elements_kind();
|
| - if (elements_kind == FAST_ELEMENTS) {
|
| - return NULL;
|
| - }
|
| - if (elements_kind == FAST_DOUBLE_ELEMENTS) {
|
| - bool dummy = true;
|
| - Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy);
|
| - if (fast_map == NULL) return NULL;
|
| - return GetMapIfPresent(fast_map, maps_list);
|
| - }
|
| - if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
|
| - bool dummy = true;
|
| - Map* double_map = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
|
| - &dummy);
|
| - // In the current implementation, if the DOUBLE map doesn't exist, the
|
| - // FAST map can't exist either.
|
| - if (double_map == NULL) return NULL;
|
| - Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy);
|
| - if (fast_map == NULL) {
|
| - return GetMapIfPresent(double_map, maps_list);
|
| - }
|
| - // Both double_map and fast_map are non-NULL. Return fast_map if it's in
|
| - // maps_list, double_map otherwise.
|
| - Map* fast_map_present = GetMapIfPresent(fast_map, maps_list);
|
| - if (fast_map_present != NULL) return fast_map_present;
|
| - return GetMapIfPresent(double_map, maps_list);
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -
|
| -MaybeObject* KeyedStoreIC::ComputePolymorphicStub(
|
| - MapList* receiver_maps,
|
| - StrictModeFlag strict_mode) {
|
| - // TODO(yangguo): <remove>
|
| - Code* generic_stub = (strict_mode == kStrictMode)
|
| - ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
|
| - : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
|
| - // </remove>
|
| -
|
| +Handle<Code> KeyedStoreIC::ComputePolymorphicStub(MapHandleList* receiver_maps,
|
| + StrictModeFlag strict_mode) {
|
| // Collect MONOMORPHIC stubs for all target_receiver_maps.
|
| - CodeList handler_ics(receiver_maps->length());
|
| - MapList transitioned_maps(receiver_maps->length());
|
| + CodeHandleList handler_ics(receiver_maps->length());
|
| + MapHandleList transitioned_maps(receiver_maps->length());
|
| for (int i = 0; i < receiver_maps->length(); ++i) {
|
| - Map* receiver_map(receiver_maps->at(i));
|
| - MaybeObject* maybe_cached_stub = NULL;
|
| - Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps);
|
| - if (transitioned_map != NULL) {
|
| - // TODO(yangguo): Enable this code!
|
| - // maybe_cached_stub = FastElementsConversionStub(
|
| - // receiver_map->elements_kind(), // original elements_kind
|
| - // transitioned_map->elements_kind(),
|
| - // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
|
| - // strict_mode_).TryGetCode();
|
| - // TODO(yangguo): <remove>
|
| - maybe_cached_stub = generic_stub;
|
| - // </remove>
|
| + Handle<Map> receiver_map(receiver_maps->at(i));
|
| + Handle<Code> cached_stub;
|
| + Handle<Map> transitioned_map =
|
| + receiver_map->FindTransitionedMap(receiver_maps);
|
| + if (!transitioned_map.is_null()) {
|
| + cached_stub = ElementsTransitionAndStoreStub(
|
| + receiver_map->elements_kind(), // original elements_kind
|
| + transitioned_map->elements_kind(),
|
| + receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
|
| + strict_mode).GetCode();
|
| } else {
|
| - maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
|
| - receiver_map, strict_mode);
|
| + cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map,
|
| + strict_mode);
|
| }
|
| - Code* cached_stub;
|
| - if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
|
| + ASSERT(!cached_stub.is_null());
|
| handler_ics.Add(cached_stub);
|
| transitioned_maps.Add(transitioned_map);
|
| }
|
| - Object* object;
|
| - KeyedStoreStubCompiler compiler(strict_mode);
|
| - MaybeObject* maybe_code = compiler.CompileStorePolymorphic(
|
| + KeyedStoreStubCompiler compiler(isolate(), strict_mode);
|
| + Handle<Code> code = compiler.CompileStorePolymorphic(
|
| receiver_maps, &handler_ics, &transitioned_maps);
|
| - if (!maybe_code->ToObject(&object)) return maybe_code;
|
| isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
|
| - PROFILE(isolate(), CodeCreateEvent(
|
| - Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG,
|
| - Code::cast(object), 0));
|
| - return object;
|
| + PROFILE(isolate(),
|
| + CodeCreateEvent(Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, *code, 0));
|
| + return code;
|
| }
|
|
|
|
|
| @@ -1835,6 +1612,12 @@
|
| if (key->IsSymbol()) {
|
| Handle<String> name = Handle<String>::cast(key);
|
|
|
| + // Handle proxies.
|
| + if (object->IsJSProxy()) {
|
| + return JSProxy::cast(*object)->SetProperty(
|
| + *name, *value, NONE, strict_mode);
|
| + }
|
| +
|
| // If the object is undefined or null it's illegal to try to set any
|
| // properties on it; throw a TypeError in that case.
|
| if (object->IsUndefined() || object->IsNull()) {
|
| @@ -1848,14 +1631,13 @@
|
| // Check if the given name is an array index.
|
| uint32_t index;
|
| if (name->AsArrayIndex(&index)) {
|
| - HandleScope scope(isolate());
|
| Handle<Object> result = SetElement(receiver, index, value, strict_mode);
|
| - if (result.is_null()) return Failure::Exception();
|
| + RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| return *value;
|
| }
|
|
|
| // Lookup the property locally in the receiver.
|
| - LookupResult lookup;
|
| + LookupResult lookup(isolate());
|
| receiver->LocalLookup(*name, &lookup);
|
|
|
| // Update inline cache and stub cache.
|
| @@ -1873,17 +1655,16 @@
|
| ASSERT(!(use_ic && object->IsJSGlobalProxy()));
|
|
|
| if (use_ic) {
|
| - Code* stub = (strict_mode == kStrictMode)
|
| + Handle<Code> stub = (strict_mode == kStrictMode)
|
| ? generic_stub_strict()
|
| : generic_stub();
|
| if (object->IsJSObject()) {
|
| - JSObject* receiver = JSObject::cast(*object);
|
| - Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
|
| - Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
|
| - if (elements_map == heap->non_strict_arguments_elements_map()) {
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| + if (receiver->elements()->map() ==
|
| + isolate()->heap()->non_strict_arguments_elements_map()) {
|
| stub = non_strict_arguments_stub();
|
| } else if (!force_generic) {
|
| - if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
|
| + if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
|
| StubKind stub_kind = STORE_NO_TRANSITION;
|
| if (receiver->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) {
|
| if (value->IsHeapNumber()) {
|
| @@ -1896,22 +1677,14 @@
|
| stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT;
|
| }
|
| }
|
| - HandleScope scope(isolate());
|
| - MaybeObject* maybe_stub = ComputeStub(receiver,
|
| - stub_kind,
|
| - strict_mode,
|
| - stub);
|
| - stub = maybe_stub->IsFailure() ?
|
| - NULL : Code::cast(maybe_stub->ToObjectUnchecked());
|
| + stub = ComputeStub(receiver, stub_kind, strict_mode, stub);
|
| }
|
| }
|
| }
|
| - if (stub != NULL) set_target(stub);
|
| + if (!stub.is_null()) set_target(*stub);
|
| }
|
|
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedStoreIC", key, state, target());
|
| -#endif
|
| + TRACE_IC("KeyedStoreIC", key, state, target());
|
|
|
| // Set the property.
|
| return Runtime::SetObjectProperty(
|
| @@ -1943,75 +1716,60 @@
|
| // Compute the code stub for this store; used for rewriting to
|
| // monomorphic state and making sure that the code stub is in the
|
| // stub cache.
|
| - MaybeObject* maybe_code = NULL;
|
| - Object* code = NULL;
|
| + Handle<Code> code;
|
|
|
| switch (type) {
|
| - case FIELD: {
|
| - maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
|
| + case FIELD:
|
| + code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| + name, receiver, lookup->GetFieldIndex(),
|
| + Handle<Map>::null(), strict_mode);
|
| break;
|
| - }
|
| - case MAP_TRANSITION: {
|
| + case MAP_TRANSITION:
|
| if (lookup->GetAttributes() == NONE) {
|
| - HandleScope scope(isolate());
|
| ASSERT(type == MAP_TRANSITION);
|
| Handle<Map> transition(lookup->GetTransitionMap());
|
| int index = transition->PropertyIndexFor(*name);
|
| - maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - *name, *receiver, index, *transition, strict_mode);
|
| + code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| + name, receiver, index, transition, strict_mode);
|
| break;
|
| }
|
| // fall through.
|
| - }
|
| - default: {
|
| + default:
|
| // Always rewrite to the generic case so that we do not
|
| // repeatedly try to rewrite.
|
| - maybe_code = (strict_mode == kStrictMode)
|
| + code = (strict_mode == kStrictMode)
|
| ? generic_stub_strict()
|
| : generic_stub();
|
| break;
|
| - }
|
| }
|
|
|
| - // 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;
|
| + ASSERT(!code.is_null());
|
|
|
| // Patch the call site depending on the state of the cache. Make
|
| // sure to always rewrite from monomorphic to megamorphic.
|
| ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
|
| if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
|
| - set_target(Code::cast(code));
|
| + set_target(*code);
|
| } else if (state == MONOMORPHIC) {
|
| set_target((strict_mode == kStrictMode)
|
| - ? megamorphic_stub_strict()
|
| - : megamorphic_stub());
|
| + ? *megamorphic_stub_strict()
|
| + : *megamorphic_stub());
|
| }
|
|
|
| -#ifdef DEBUG
|
| - TraceIC("KeyedStoreIC", name, state, target());
|
| -#endif
|
| + TRACE_IC("KeyedStoreIC", name, state, target());
|
| }
|
|
|
|
|
| +#undef TRACE_IC
|
| +
|
| +
|
| // ----------------------------------------------------------------------------
|
| // Static IC stub generators.
|
| //
|
|
|
| -static JSFunction* CompileFunction(Isolate* isolate,
|
| - JSFunction* function) {
|
| - // Compile now with optimization.
|
| - HandleScope scope(isolate);
|
| - Handle<JSFunction> function_handle(function, isolate);
|
| - CompileLazy(function_handle, CLEAR_EXCEPTION);
|
| - return *function_handle;
|
| -}
|
| -
|
| -
|
| // Used from ic-<arch>.cc.
|
| RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope(isolate);
|
| ASSERT(args.length() == 2);
|
| CallIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| @@ -2020,45 +1778,46 @@
|
| extra_ic_state,
|
| args.at<Object>(0),
|
| args.at<String>(1));
|
| - Object* result;
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| + // Result could be a function or a failure.
|
| + JSFunction* raw_function = NULL;
|
| + if (!maybe_result->To(&raw_function)) return maybe_result;
|
|
|
| // The first time the inline cache is updated may be the first time the
|
| - // function it references gets called. If the function was lazily compiled
|
| + // function it references gets called. If the function is lazily compiled
|
| // then the first call will trigger a compilation. We check for this case
|
| // and we do the compilation immediately, instead of waiting for the stub
|
| - // currently attached to the JSFunction object to trigger compilation. We
|
| - // do this in the case where we know that the inline cache is inside a loop,
|
| - // because then we know that we want to optimize the function.
|
| - if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
|
| - return result;
|
| - }
|
| - return CompileFunction(isolate, JSFunction::cast(result));
|
| + // currently attached to the JSFunction object to trigger compilation.
|
| + if (raw_function->is_compiled()) return raw_function;
|
| +
|
| + Handle<JSFunction> function(raw_function);
|
| + JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
|
| + return *function;
|
| }
|
|
|
|
|
| // Used from ic-<arch>.cc.
|
| RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope(isolate);
|
| ASSERT(args.length() == 2);
|
| KeyedCallIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| - Object* result;
|
| - { MaybeObject* maybe_result =
|
| + MaybeObject* maybe_result =
|
| ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1));
|
| - if (!maybe_result->ToObject(&result)) return maybe_result;
|
| - }
|
| + // Result could be a function or a failure.
|
| + JSFunction* raw_function = NULL;
|
| + if (!maybe_result->To(&raw_function)) return maybe_result;
|
|
|
| - if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
|
| - return result;
|
| - }
|
| - return CompileFunction(isolate, JSFunction::cast(result));
|
| + if (raw_function->is_compiled()) return raw_function;
|
| +
|
| + Handle<JSFunction> function(raw_function);
|
| + JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
|
| + return *function;
|
| }
|
|
|
|
|
| // 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]);
|
| @@ -2068,7 +1827,7 @@
|
|
|
| // Used from ic-<arch>.cc
|
| RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope(isolate);
|
| ASSERT(args.length() == 2);
|
| KeyedLoadIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| @@ -2077,7 +1836,7 @@
|
|
|
|
|
| RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope(isolate);
|
| ASSERT(args.length() == 2);
|
| KeyedLoadIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| @@ -2087,7 +1846,7 @@
|
|
|
| // Used from ic-<arch>.cc.
|
| RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope;
|
| ASSERT(args.length() == 3);
|
| StoreIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| @@ -2156,7 +1915,7 @@
|
|
|
| // Used from ic-<arch>.cc.
|
| RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope(isolate);
|
| ASSERT(args.length() == 3);
|
| KeyedStoreIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
| @@ -2190,7 +1949,7 @@
|
|
|
|
|
| RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
|
| - NoHandleAllocation na;
|
| + HandleScope scope(isolate);
|
| ASSERT(args.length() == 3);
|
| KeyedStoreIC ic(isolate);
|
| IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
|
|