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]); |