vendor/v8/src/ic.cc in mustang-0.0.1 vs vendor/v8/src/ic.cc in mustang-0.1.0

- old
+ new

@@ -63,12 +63,12 @@ State old_state, Code* new_target, const char* extra_info) { if (FLAG_trace_ic) { State new_state = StateFrom(new_target, - Heap::undefined_value(), - Heap::undefined_value()); + HEAP->undefined_value(), + HEAP->undefined_value()); PrintF("[%s (%c->%c)%s", type, TransitionMarkFromState(old_state), TransitionMarkFromState(new_state), extra_info); name->Print(); @@ -76,15 +76,17 @@ } } #endif -IC::IC(FrameDepth depth) { +IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { + ASSERT(isolate == Isolate::Current()); // To improve the performance of the (much used) IC code, we unfold // a few levels of the stack frame iteration code. This yields a // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. - const Address entry = Top::c_entry_fp(Top::GetCurrentThread()); + const Address entry = + Isolate::c_entry_fp(isolate->thread_local_top()); Address* pc_address = reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); // If there's another JavaScript frame on the stack, we need to look // one frame further down the stack to find the frame pointer and @@ -134,13 +136,15 @@ return addr + delta; } #endif -static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup, +static bool HasNormalObjectsInPrototypeChain(Isolate* isolate, + LookupResult* lookup, Object* receiver) { - Object* end = lookup->IsProperty() ? lookup->holder() : Heap::null_value(); + Object* end = lookup->IsProperty() + ? lookup->holder() : isolate->heap()->null_value(); for (Object* current = receiver; current != end; current = current->GetPrototype()) { if (current->IsJSObject() && !JSObject::cast(current)->HasFastProperties() && @@ -229,11 +233,11 @@ } RelocInfo::Mode IC::ComputeMode() { Address addr = address(); - Code* code = Code::cast(Heap::FindCodeObject(addr)); + Code* code = Code::cast(isolate()->heap()->FindCodeObject(addr)); for (RelocIterator it(code, RelocInfo::kCodeTargetMask); !it.done(); it.next()) { RelocInfo* info = it.rinfo(); if (info->pc() == addr) return info->rmode(); } @@ -243,22 +247,23 @@ Failure* IC::TypeError(const char* type, Handle<Object> object, Handle<Object> key) { - HandleScope scope; + HandleScope scope(isolate()); Handle<Object> args[2] = { key, object }; - Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2)); - return Top::Throw(*error); + Handle<Object> error = isolate()->factory()->NewTypeError( + type, HandleVector(args, 2)); + return isolate()->Throw(*error); } Failure* IC::ReferenceError(const char* type, Handle<String> name) { - HandleScope scope; - Handle<Object> error = - Factory::NewReferenceError(type, HandleVector(&name, 1)); - return Top::Throw(*error); + HandleScope scope(isolate()); + Handle<Object> error = isolate()->factory()->NewReferenceError( + type, HandleVector(&name, 1)); + return isolate()->Throw(*error); } void IC::Clear(Address address) { Code* target = GetTargetAtAddress(address); @@ -266,13 +271,17 @@ // Don't clear debug break inline cache as it will remove the break point. if (target->ic_state() == DEBUG_BREAK) return; switch (target->kind()) { case Code::LOAD_IC: return LoadIC::Clear(address, target); - case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); + case Code::KEYED_LOAD_IC: + case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC: + return KeyedLoadIC::Clear(address, target); case Code::STORE_IC: return StoreIC::Clear(address, target); - case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); + case Code::KEYED_STORE_IC: + case Code::KEYED_EXTERNAL_ARRAY_STORE_IC: + return KeyedStoreIC::Clear(address, target); case Code::CALL_IC: return CallIC::Clear(address, target); case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); case Code::BINARY_OP_IC: case Code::TYPE_RECORDING_BINARY_OP_IC: case Code::COMPARE_IC: @@ -286,21 +295,22 @@ void CallICBase::Clear(Address address, Code* target) { State state = target->ic_state(); if (state == UNINITIALIZED) return; Code* code = - StubCache::FindCallInitialize(target->arguments_count(), - target->ic_in_loop(), - target->kind()); + Isolate::Current()->stub_cache()->FindCallInitialize( + target->arguments_count(), + target->ic_in_loop(), + target->kind()); SetTargetAtAddress(address, code); } void KeyedLoadIC::ClearInlinedVersion(Address address) { // Insert null as the map to check for to make sure the map check fails // sending control flow to the IC instead of the inlined version. - PatchInlinedLoad(address, Heap::null_value()); + PatchInlinedLoad(address, HEAP->null_value()); } void KeyedLoadIC::Clear(Address address, Code* target) { if (target->ic_state() == UNINITIALIZED) return; @@ -314,14 +324,15 @@ void LoadIC::ClearInlinedVersion(Address address) { // Reset the map check of the inlined inobject property load (if // present) to guarantee failure by holding an invalid map (the null // value). The offset can be patched to anything. - PatchInlinedLoad(address, Heap::null_value(), 0); + Heap* heap = HEAP; + PatchInlinedLoad(address, heap->null_value(), 0); PatchInlinedContextualLoad(address, - Heap::null_value(), - Heap::null_value(), + heap->null_value(), + heap->null_value(), true); } void LoadIC::Clear(Address address, Code* target) { @@ -333,42 +344,45 @@ void StoreIC::ClearInlinedVersion(Address address) { // Reset the map check of the inlined inobject property store (if // present) to guarantee failure by holding an invalid map (the null // value). The offset can be patched to anything. - PatchInlinedStore(address, Heap::null_value(), 0); + PatchInlinedStore(address, HEAP->null_value(), 0); } void StoreIC::Clear(Address address, Code* target) { if (target->ic_state() == UNINITIALIZED) return; ClearInlinedVersion(address); SetTargetAtAddress(address, - target->extra_ic_state() == kStoreICStrict + (target->extra_ic_state() == kStrictMode) ? initialize_stub_strict() : initialize_stub()); } void KeyedStoreIC::ClearInlinedVersion(Address address) { // Insert null as the elements map to check for. This will make // sure that the elements fast-case map check fails so that control // flows to the IC instead of the inlined version. - PatchInlinedStore(address, Heap::null_value()); + PatchInlinedStore(address, HEAP->null_value()); } void KeyedStoreIC::RestoreInlinedVersion(Address address) { // Restore the fast-case elements map check so that the inlined // version can be used again. - PatchInlinedStore(address, Heap::fixed_array_map()); + PatchInlinedStore(address, HEAP->fixed_array_map()); } void KeyedStoreIC::Clear(Address address, Code* target) { if (target->ic_state() == UNINITIALIZED) return; - SetTargetAtAddress(address, initialize_stub()); + SetTargetAtAddress(address, + (target->extra_ic_state() == kStrictMode) + ? initialize_stub_strict() + : initialize_stub()); } static bool HasInterceptorGetter(JSObject* object) { return !object->GetNamedInterceptor()->getter()->IsUndefined(); @@ -414,12 +428,12 @@ } } Object* CallICBase::TryCallAsFunction(Object* object) { - HandleScope scope; - Handle<Object> target(object); + HandleScope scope(isolate()); + Handle<Object> target(object, isolate()); Handle<Object> delegate = Execution::GetFunctionDelegate(target); if (delegate->IsJSFunction()) { // Patch the receiver and use the delegate as the function to // invoke. This is used for invoking objects as if they were @@ -450,11 +464,11 @@ // Change the receiver to the result of calling ToObject on it. const int argc = this->target()->arguments_count(); StackFrameLocator locator; JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); int index = frame->ComputeExpressionsCount() - (argc + 1); - frame->SetExpression(index, *Factory::ToObject(object)); + frame->SetExpression(index, *isolate()->factory()->ToObject(object)); } } MaybeObject* CallICBase::LoadFunction(State state, @@ -522,11 +536,11 @@ } } ASSERT(!result->IsTheHole()); - HandleScope scope; + 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 @@ -534,15 +548,16 @@ ReceiverToObjectIfRequired(result_handle, object); if (result_handle->IsJSFunction()) { #ifdef ENABLE_DEBUGGER_SUPPORT // Handle stepping into a function if step into is active. - if (Debug::StepInActive()) { + 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)); - Debug::HandleStepIn(function, object, fp(), false); + Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate()); + debug->HandleStepIn(function, object, fp(), false); return *function; } #endif return *result_handle; @@ -564,11 +579,11 @@ JSFunction* function = lookup->GetConstantFunction(); if (!function->shared()->HasBuiltinFunctionId()) return false; // Fetch the arguments passed to the called function. const int argc = target()->arguments_count(); - Address entry = Top::c_entry_fp(Top::GetCurrentThread()); + Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); Arguments args(argc + 1, &Memory::Object_at(fp + StandardFrameConstants::kCallerSPOffset + argc * kPointerSize)); @@ -614,32 +629,33 @@ InLoopFlag in_loop = target()->ic_in_loop(); MaybeObject* maybe_code = NULL; switch (lookup->type()) { case FIELD: { int index = lookup->GetFieldIndex(); - maybe_code = StubCache::ComputeCallField(argc, - in_loop, - kind_, - *name, - *object, - lookup->holder(), - index); + maybe_code = isolate()->stub_cache()->ComputeCallField(argc, + in_loop, + kind_, + *name, + *object, + lookup->holder(), + index); break; } 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 = StubCache::ComputeCallConstant(argc, - in_loop, - kind_, - extra_ic_state, - *name, - *object, - lookup->holder(), - function); + maybe_code = + isolate()->stub_cache()->ComputeCallConstant(argc, + in_loop, + kind_, + extra_ic_state, + *name, + *object, + lookup->holder(), + function); break; } case NORMAL: { if (!object->IsJSObject()) return NULL; Handle<JSObject> receiver = Handle<JSObject>::cast(object); @@ -648,39 +664,40 @@ 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 = StubCache::ComputeCallGlobal(argc, - in_loop, - kind_, - *name, - *receiver, - global, - cell, - function); + maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc, + in_loop, + kind_, + *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 = StubCache::ComputeCallNormal(argc, - in_loop, - kind_, - *name, - *receiver); + maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc, + in_loop, + kind_, + *name, + *receiver); } break; } case INTERCEPTOR: { ASSERT(HasInterceptorGetter(lookup->holder())); - maybe_code = StubCache::ComputeCallInterceptor(argc, - kind_, - *name, - *object, - lookup->holder()); + maybe_code = isolate()->stub_cache()->ComputeCallInterceptor( + argc, + kind_, + *name, + *object, + lookup->holder()); break; } default: maybe_code = NULL; break; @@ -696,11 +713,12 @@ Handle<String> name) { // Bail out if we didn't find a result. if (!lookup->IsProperty() || !lookup->IsCacheable()) return; if (lookup->holder() != *object && - HasNormalObjectsInPrototypeChain(lookup, object->GetPrototype())) { + HasNormalObjectsInPrototypeChain( + isolate(), lookup, object->GetPrototype())) { // Suppress optimization for prototype chains with slow properties objects // in the middle. return; } @@ -711,11 +729,13 @@ bool had_proto_failure = false; 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 = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); + maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc, + in_loop, + kind_); } else if (state == MONOMORPHIC) { if (kind_ == Code::CALL_IC && TryUpdateExtraICState(lookup, object, &extra_ic_state)) { maybe_code = ComputeMonomorphicStub(lookup, state, @@ -731,11 +751,13 @@ state, extra_ic_state, object, name); } else { - maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); + maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc, + in_loop, + kind_); } } else { maybe_code = ComputeMonomorphicStub(lookup, state, extra_ic_state, @@ -759,11 +781,11 @@ // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. Map* map = JSObject::cast(object->IsJSObject() ? *object : object->GetPrototype())->map(); // Update the stub cache. - StubCache::Set(*name, map, Code::cast(code)); + isolate()->stub_cache()->Set(*name, map, Code::cast(code)); } USE(had_proto_failure); #ifdef DEBUG if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; @@ -788,11 +810,11 @@ } if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { int argc = target()->arguments_count(); InLoopFlag in_loop = target()->ic_in_loop(); - MaybeObject* maybe_code = StubCache::ComputeCallMegamorphic( + MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( argc, in_loop, Code::KEYED_CALL_IC); Object* code; if (maybe_code->ToObject(&code)) { set_target(Code::cast(code)); #ifdef DEBUG @@ -800,12 +822,13 @@ "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : ""); #endif } } - HandleScope scope; + HandleScope scope(isolate()); Handle<Object> result = GetProperty(object, key); + RETURN_IF_EMPTY_HANDLE(isolate(), 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, object); @@ -842,60 +865,68 @@ // Use specialized code for getting the length of strings and // string wrapper objects. The length property of string wrapper // objects is read-only and therefore always returns the length of // the underlying string value. See ECMA-262 15.5.5.1. if ((object->IsString() || object->IsStringWrapper()) && - name->Equals(Heap::length_symbol())) { - HandleScope scope; + name->Equals(isolate()->heap()->length_symbol())) { + HandleScope scope(isolate()); #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); #endif if (state == PREMONOMORPHIC) { if (object->IsString()) { Map* map = HeapObject::cast(*object)->map(); const int offset = String::kLengthOffset; PatchInlinedLoad(address(), map, offset); - set_target(Builtins::builtin(Builtins::LoadIC_StringLength)); + set_target(isolate()->builtins()->builtin( + Builtins::kLoadIC_StringLength)); } else { - set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength)); + set_target(isolate()->builtins()->builtin( + Builtins::kLoadIC_StringWrapperLength)); } } else if (state == MONOMORPHIC && object->IsStringWrapper()) { - set_target(Builtins::builtin(Builtins::LoadIC_StringWrapperLength)); + set_target(isolate()->builtins()->builtin( + Builtins::kLoadIC_StringWrapperLength)); } else { set_target(non_monomorphic_stub); } // Get the string if we have a string wrapper object. if (object->IsJSValue()) { - object = Handle<Object>(Handle<JSValue>::cast(object)->value()); + object = Handle<Object>(Handle<JSValue>::cast(object)->value(), + isolate()); } return Smi::FromInt(String::cast(*object)->length()); } // Use specialized code for getting the length of arrays. - if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { + if (object->IsJSArray() && + name->Equals(isolate()->heap()->length_symbol())) { #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); #endif if (state == PREMONOMORPHIC) { Map* map = HeapObject::cast(*object)->map(); const int offset = JSArray::kLengthOffset; PatchInlinedLoad(address(), map, offset); - set_target(Builtins::builtin(Builtins::LoadIC_ArrayLength)); + set_target(isolate()->builtins()->builtin( + Builtins::kLoadIC_ArrayLength)); } else { set_target(non_monomorphic_stub); } return JSArray::cast(*object)->length(); } // Use specialized code for getting prototype of functions. - if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) && + if (object->IsJSFunction() && + name->Equals(isolate()->heap()->prototype_symbol()) && JSFunction::cast(*object)->should_have_prototype()) { #ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); #endif if (state == PREMONOMORPHIC) { - set_target(Builtins::builtin(Builtins::LoadIC_FunctionPrototype)); + set_target(isolate()->builtins()->builtin( + Builtins::kLoadIC_FunctionPrototype)); } else { set_target(non_monomorphic_stub); } return Accessors::FunctionGetPrototype(*object, 0); } @@ -913,11 +944,11 @@ // If we did not find a property, check if we need to throw an exception. if (!lookup.IsProperty()) { if (FLAG_strict || IsContextual(object)) { return ReferenceError("not_defined", name); } - LOG(SuspectReadEvent(*name, *object)); + LOG(isolate(), SuspectReadEvent(*name, *object)); } bool can_be_inlined_precheck = FLAG_use_ic && lookup.IsProperty() && @@ -964,11 +995,11 @@ map, cell, lookup.IsDontDelete())) { set_target(megamorphic_stub()); TRACE_IC_NAMED("[LoadIC : inline contextual patch %s]\n", name); - ASSERT(cell->value() != Heap::the_hole_value()); + ASSERT(cell->value() != isolate()->heap()->the_hole_value()); return cell->value(); } } else { if (FLAG_use_ic && state == PREMONOMORPHIC) { TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inlinable)]\n", name); @@ -1011,11 +1042,11 @@ // Loading properties from values is not common, so don't try to // deal with non-JS objects here. if (!object->IsJSObject()) return; Handle<JSObject> receiver = Handle<JSObject>::cast(object); - if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; + if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; // Compute the code stub for this load. MaybeObject* maybe_code = NULL; Object* code; if (state == UNINITIALIZED) { @@ -1023,59 +1054,62 @@ // Set the target to the pre monomorphic stub to delay // setting the monomorphic state. maybe_code = pre_monomorphic_stub(); } else if (!lookup->IsProperty()) { // Nonexistent property. The result is undefined. - maybe_code = StubCache::ComputeLoadNonexistent(*name, *receiver); + maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name, + *receiver); } else { // Compute monomorphic stub. switch (lookup->type()) { case FIELD: { - maybe_code = StubCache::ComputeLoadField(*name, *receiver, - lookup->holder(), - lookup->GetFieldIndex()); + maybe_code = isolate()->stub_cache()->ComputeLoadField( + *name, + *receiver, + lookup->holder(), + lookup->GetFieldIndex()); break; } case CONSTANT_FUNCTION: { Object* constant = lookup->GetConstantFunction(); - maybe_code = StubCache::ComputeLoadConstant(*name, *receiver, - lookup->holder(), constant); + maybe_code = isolate()->stub_cache()->ComputeLoadConstant( + *name, *receiver, lookup->holder(), constant); break; } case NORMAL: { if (lookup->holder()->IsGlobalObject()) { GlobalObject* global = GlobalObject::cast(lookup->holder()); JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); - maybe_code = StubCache::ComputeLoadGlobal(*name, + maybe_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 = StubCache::ComputeLoadNormal(); + maybe_code = isolate()->stub_cache()->ComputeLoadNormal(); } break; } case CALLBACKS: { if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); if (v8::ToCData<Address>(callback->getter()) == 0) return; - maybe_code = StubCache::ComputeLoadCallback(*name, *receiver, - lookup->holder(), callback); + maybe_code = isolate()->stub_cache()->ComputeLoadCallback( + *name, *receiver, lookup->holder(), callback); break; } case INTERCEPTOR: { ASSERT(HasInterceptorGetter(lookup->holder())); - maybe_code = StubCache::ComputeLoadInterceptor(*name, *receiver, - lookup->holder()); + maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor( + *name, *receiver, lookup->holder()); break; } default: return; } @@ -1095,11 +1129,11 @@ // Cache code holding map should be consistent with // GenerateMonomorphicCacheProbe. Map* map = JSObject::cast(object->IsJSObject() ? *object : object->GetPrototype())->map(); - StubCache::Set(*name, map, Code::cast(code)); + isolate()->stub_cache()->Set(*name, map, Code::cast(code)); } #ifdef DEBUG TraceIC("LoadIC", name, state, target()); #endif @@ -1107,10 +1141,20 @@ MaybeObject* KeyedLoadIC::Load(State state, Handle<Object> object, Handle<Object> key) { + // 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())) { + key = isolate()->factory()->nan_symbol(); + } else if (key->IsUndefined()) { + key = isolate()->factory()->undefined_symbol(); + } + if (key->IsSymbol()) { Handle<String> name = Handle<String>::cast(key); // If the object is undefined or null it's illegal to try to get any // of its properties; throw a TypeError in that case. @@ -1120,46 +1164,52 @@ if (FLAG_use_ic) { // TODO(1073): don't ignore the current stub state. // Use specialized code for getting the length of strings. - if (object->IsString() && name->Equals(Heap::length_symbol())) { + if (object->IsString() && + name->Equals(isolate()->heap()->length_symbol())) { Handle<String> string = Handle<String>::cast(object); Object* code = NULL; { MaybeObject* maybe_code = - StubCache::ComputeKeyedLoadStringLength(*name, *string); + 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 return Smi::FromInt(string->length()); } // Use specialized code for getting the length of arrays. - if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { + if (object->IsJSArray() && + name->Equals(isolate()->heap()->length_symbol())) { Handle<JSArray> array = Handle<JSArray>::cast(object); Object* code; { MaybeObject* maybe_code = - StubCache::ComputeKeyedLoadArrayLength(*name, *array); + 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(); } // Use specialized code for getting prototype of functions. - if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) && + if (object->IsJSFunction() && + name->Equals(isolate()->heap()->prototype_symbol()) && JSFunction::cast(*object)->should_have_prototype()) { Handle<JSFunction> function = Handle<JSFunction>::cast(object); Object* code; { MaybeObject* maybe_code = - StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); + 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()); @@ -1170,14 +1220,14 @@ // Check if the name is trivially convertible to an index and get // the element or char if so. uint32_t index = 0; if (name->AsArrayIndex(&index)) { - HandleScope scope; + HandleScope scope(isolate()); // Rewrite to the generic keyed load stub. if (FLAG_use_ic) set_target(generic_stub()); - return Runtime::GetElementOrCharAt(object, index); + return Runtime::GetElementOrCharAt(isolate(), object, index); } // Named lookup. LookupResult lookup; LookupForRead(*object, *name, &lookup); @@ -1223,25 +1273,20 @@ stub = string_stub(); } else if (object->IsJSObject()) { Handle<JSObject> receiver = Handle<JSObject>::cast(object); if (receiver->HasExternalArrayElements()) { MaybeObject* probe = - StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, - false); + isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( + *receiver, false, kNonStrictMode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } else if (receiver->HasIndexedInterceptor()) { stub = indexed_interceptor_stub(); - } else if (receiver->HasPixelElements()) { - MaybeObject* probe = - StubCache::ComputeKeyedLoadPixelArray(*receiver); - stub = probe->IsFailure() ? - NULL : Code::cast(probe->ToObjectUnchecked()); } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { MaybeObject* probe = - StubCache::ComputeKeyedLoadSpecialized(*receiver); + isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } } } @@ -1263,11 +1308,11 @@ PatchInlinedLoad(address(), map); } } // Get the property. - return Runtime::GetObjectProperty(object, key); + return Runtime::GetObjectProperty(isolate(), object, key); } void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, Handle<Object> object, Handle<String> name) { @@ -1275,11 +1320,11 @@ if (!lookup->IsProperty() || !lookup->IsCacheable()) return; if (!object->IsJSObject()) return; Handle<JSObject> receiver = Handle<JSObject>::cast(object); - if (HasNormalObjectsInPrototypeChain(lookup, *object)) return; + if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; // Compute the code stub for this load. MaybeObject* maybe_code = NULL; Object* code; @@ -1290,38 +1335,33 @@ maybe_code = pre_monomorphic_stub(); } else { // Compute a monomorphic stub. switch (lookup->type()) { case FIELD: { - maybe_code = StubCache::ComputeKeyedLoadField(*name, *receiver, - lookup->holder(), - lookup->GetFieldIndex()); + maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField( + *name, *receiver, lookup->holder(), lookup->GetFieldIndex()); break; } case CONSTANT_FUNCTION: { Object* constant = lookup->GetConstantFunction(); - maybe_code = StubCache::ComputeKeyedLoadConstant(*name, - *receiver, - lookup->holder(), - constant); + maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant( + *name, *receiver, lookup->holder(), constant); break; } case CALLBACKS: { if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); if (v8::ToCData<Address>(callback->getter()) == 0) return; - maybe_code = StubCache::ComputeKeyedLoadCallback(*name, - *receiver, - lookup->holder(), - callback); + maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback( + *name, *receiver, lookup->holder(), callback); break; } case INTERCEPTOR: { ASSERT(HasInterceptorGetter(lookup->holder())); - maybe_code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver, - lookup->holder()); + maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor( + *name, *receiver, lookup->holder()); break; } default: { // Always rewrite to the generic case so that we do not // repeatedly try to rewrite. @@ -1380,45 +1420,53 @@ return true; } MaybeObject* StoreIC::Store(State state, - Code::ExtraICState extra_ic_state, + StrictModeFlag strict_mode, Handle<Object> object, Handle<String> name, Handle<Object> value) { // 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()) { return TypeError("non_object_property_store", object, name); } - // Ignore stores where the receiver is not a JSObject. - if (!object->IsJSObject()) return *value; + if (!object->IsJSObject()) { + // The length property of string values is read-only. Throw in strict mode. + if (strict_mode == kStrictMode && object->IsString() && + name->Equals(isolate()->heap()->length_symbol())) { + return TypeError("strict_read_only_property", object, name); + } + // Ignore stores where the receiver is not a JSObject. + return *value; + } + Handle<JSObject> receiver = Handle<JSObject>::cast(object); // Check if the given name is an array index. uint32_t index; if (name->AsArrayIndex(&index)) { - HandleScope scope; - Handle<Object> result = SetElement(receiver, index, value); + HandleScope scope(isolate()); + Handle<Object> result = SetElement(receiver, index, value, strict_mode); if (result.is_null()) return Failure::Exception(); return *value; } // Use specialized code for setting the length of arrays. if (receiver->IsJSArray() - && name->Equals(Heap::length_symbol()) + && name->Equals(isolate()->heap()->length_symbol()) && receiver->AllowsSetElementsLength()) { #ifdef DEBUG if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); #endif - Builtins::Name target = (extra_ic_state == kStoreICStrict) - ? Builtins::StoreIC_ArrayLength_Strict - : Builtins::StoreIC_ArrayLength; - set_target(Builtins::builtin(target)); - return receiver->SetProperty(*name, *value, NONE); + Builtins::Name target = (strict_mode == kStrictMode) + ? Builtins::kStoreIC_ArrayLength_Strict + : Builtins::kStoreIC_ArrayLength; + set_target(isolate()->builtins()->builtin(target)); + return receiver->SetProperty(*name, *value, NONE, strict_mode); } // Lookup the property locally in the receiver. if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { LookupResult lookup; @@ -1438,17 +1486,19 @@ int index = lookup.GetFieldIndex() - map->inobject_properties(); if (index < 0) { // Index is an offset from the end of the object. int offset = map->instance_size() + (index * kPointerSize); if (PatchInlinedStore(address(), map, offset)) { - set_target(megamorphic_stub()); + set_target((strict_mode == kStrictMode) + ? megamorphic_stub_strict() + : megamorphic_stub()); #ifdef DEBUG if (FLAG_trace_ic) { PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); } #endif - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); #ifdef DEBUG } else { if (FLAG_trace_ic) { PrintF("[StoreIC : no inline patch %s (patching failed)]\n", @@ -1471,23 +1521,28 @@ } } // If no inlined store ic was patched, generate a stub for this // store. - UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value); + UpdateCaches(&lookup, state, strict_mode, receiver, name, value); } else { - // Strict mode doesn't allow setting non-existent global property. - if (extra_ic_state == kStoreICStrict && IsContextual(object)) { - return ReferenceError("not_defined", name); + // Strict mode doesn't allow setting non-existent global property + // or an assignment to a read only property. + if (strict_mode == kStrictMode) { + if (lookup.IsFound() && lookup.IsReadOnly()) { + return TypeError("strict_read_only_property", object, name); + } else if (IsContextual(object)) { + return ReferenceError("not_defined", name); + } } } } if (receiver->IsJSGlobalProxy()) { // Generate a generic stub that goes to the runtime when we see a global // proxy as receiver. - Code* stub = (extra_ic_state == kStoreICStrict) + Code* stub = (strict_mode == kStrictMode) ? global_proxy_stub_strict() : global_proxy_stub(); if (target() != stub) { set_target(stub); #ifdef DEBUG @@ -1495,17 +1550,17 @@ #endif } } // Set the property. - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); } void StoreIC::UpdateCaches(LookupResult* lookup, State state, - Code::ExtraICState extra_ic_state, + StrictModeFlag strict_mode, Handle<JSObject> receiver, Handle<String> name, Handle<Object> value) { // Skip JSGlobalProxy. ASSERT(!receiver->IsJSGlobalProxy()); @@ -1522,52 +1577,52 @@ // stub cache. MaybeObject* maybe_code = NULL; Object* code = NULL; switch (type) { case FIELD: { - maybe_code = StubCache::ComputeStoreField( - *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); + maybe_code = isolate()->stub_cache()->ComputeStoreField( + *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); break; } case MAP_TRANSITION: { if (lookup->GetAttributes() != NONE) return; - HandleScope scope; + HandleScope scope(isolate()); ASSERT(type == MAP_TRANSITION); Handle<Map> transition(lookup->GetTransitionMap()); int index = transition->PropertyIndexFor(*name); - maybe_code = StubCache::ComputeStoreField( - *name, *receiver, index, *transition, extra_ic_state); + maybe_code = isolate()->stub_cache()->ComputeStoreField( + *name, *receiver, index, *transition, strict_mode); break; } 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 = StubCache::ComputeStoreGlobal( - *name, *global, cell, extra_ic_state); + maybe_code = isolate()->stub_cache()->ComputeStoreGlobal( + *name, *global, cell, strict_mode); } else { if (lookup->holder() != *receiver) return; - maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); + maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); } break; } case CALLBACKS: { if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); if (v8::ToCData<Address>(callback->setter()) == 0) return; - maybe_code = StubCache::ComputeStoreCallback( - *name, *receiver, callback, extra_ic_state); + maybe_code = isolate()->stub_cache()->ComputeStoreCallback( + *name, *receiver, callback, strict_mode); break; } case INTERCEPTOR: { ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); - maybe_code = StubCache::ComputeStoreInterceptor( - *name, *receiver, extra_ic_state); + maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor( + *name, *receiver, strict_mode); break; } default: return; } @@ -1580,26 +1635,29 @@ if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { set_target(Code::cast(code)); } else if (state == MONOMORPHIC) { // Only move to megamorphic if the target changes. if (target() != Code::cast(code)) { - set_target(extra_ic_state == kStoreICStrict + set_target((strict_mode == kStrictMode) ? megamorphic_stub_strict() : megamorphic_stub()); } } else if (state == MEGAMORPHIC) { // Update the stub cache. - StubCache::Set(*name, receiver->map(), Code::cast(code)); + isolate()->stub_cache()->Set(*name, + receiver->map(), + Code::cast(code)); } #ifdef DEBUG TraceIC("StoreIC", name, state, target()); #endif } MaybeObject* KeyedStoreIC::Store(State state, + StrictModeFlag strict_mode, Handle<Object> object, Handle<Object> key, Handle<Object> value) { if (key->IsSymbol()) { Handle<String> name = Handle<String>::cast(key); @@ -1615,67 +1673,67 @@ Handle<JSObject> receiver = Handle<JSObject>::cast(object); // Check if the given name is an array index. uint32_t index; if (name->AsArrayIndex(&index)) { - HandleScope scope; - Handle<Object> result = SetElement(receiver, index, value); + HandleScope scope(isolate()); + Handle<Object> result = SetElement(receiver, index, value, strict_mode); if (result.is_null()) return Failure::Exception(); return *value; } // Lookup the property locally in the receiver. LookupResult lookup; receiver->LocalLookup(*name, &lookup); // Update inline cache and stub cache. if (FLAG_use_ic) { - UpdateCaches(&lookup, state, receiver, name, value); + UpdateCaches(&lookup, state, strict_mode, receiver, name, value); } // Set the property. - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); } // Do not use ICs for objects that require access checks (including // the global object). bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); ASSERT(!(use_ic && object->IsJSGlobalProxy())); if (use_ic) { - Code* stub = generic_stub(); + Code* stub = + (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); if (state == UNINITIALIZED) { if (object->IsJSObject()) { Handle<JSObject> receiver = Handle<JSObject>::cast(object); if (receiver->HasExternalArrayElements()) { MaybeObject* probe = - StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true); + isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray( + *receiver, true, strict_mode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); - } else if (receiver->HasPixelElements()) { - MaybeObject* probe = - StubCache::ComputeKeyedStorePixelArray(*receiver); - stub = probe->IsFailure() ? - NULL : Code::cast(probe->ToObjectUnchecked()); } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { MaybeObject* probe = - StubCache::ComputeKeyedStoreSpecialized(*receiver); + isolate()->stub_cache()->ComputeKeyedStoreSpecialized( + *receiver, strict_mode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } } } if (stub != NULL) set_target(stub); } // Set the property. - return Runtime::SetObjectProperty(object, key, value, NONE); + return Runtime::SetObjectProperty( + isolate(), object , key, value, NONE, strict_mode); } void KeyedStoreIC::UpdateCaches(LookupResult* lookup, State state, + StrictModeFlag strict_mode, Handle<JSObject> receiver, Handle<String> name, Handle<Object> value) { // Skip JSGlobalProxy. if (receiver->IsJSGlobalProxy()) return; @@ -1698,30 +1756,32 @@ MaybeObject* maybe_code = NULL; Object* code = NULL; switch (type) { case FIELD: { - maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, - lookup->GetFieldIndex()); + maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( + *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); break; } case MAP_TRANSITION: { if (lookup->GetAttributes() == NONE) { - HandleScope scope; + HandleScope scope(isolate()); ASSERT(type == MAP_TRANSITION); Handle<Map> transition(lookup->GetTransitionMap()); int index = transition->PropertyIndexFor(*name); - maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, - index, *transition); + maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField( + *name, *receiver, index, *transition, strict_mode); break; } // fall through. } default: { // Always rewrite to the generic case so that we do not // repeatedly try to rewrite. - maybe_code = generic_stub(); + maybe_code = (strict_mode == kStrictMode) + ? generic_stub_strict() + : generic_stub(); break; } } // If we're unable to compute the stub (not enough memory left), we @@ -1732,11 +1792,13 @@ // sure to always rewrite from monomorphic to megamorphic. ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); if (state == UNINITIALIZED || state == PREMONOMORPHIC) { set_target(Code::cast(code)); } else if (state == MONOMORPHIC) { - set_target(megamorphic_stub()); + set_target((strict_mode == kStrictMode) + ? megamorphic_stub_strict() + : megamorphic_stub()); } #ifdef DEBUG TraceIC("KeyedStoreIC", name, state, target()); #endif @@ -1745,29 +1807,30 @@ // ---------------------------------------------------------------------------- // Static IC stub generators. // -static JSFunction* CompileFunction(JSFunction* function, +static JSFunction* CompileFunction(Isolate* isolate, + JSFunction* function, InLoopFlag in_loop) { // Compile now with optimization. - HandleScope scope; - Handle<JSFunction> function_handle(function); + HandleScope scope(isolate); + Handle<JSFunction> function_handle(function, isolate); if (in_loop == IN_LOOP) { CompileLazyInLoop(function_handle, CLEAR_EXCEPTION); } else { CompileLazy(function_handle, CLEAR_EXCEPTION); } return *function_handle; } // Used from ic-<arch>.cc. -MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 2); - CallIC ic; + CallIC ic(isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); MaybeObject* maybe_result = ic.LoadFunction(state, extra_ic_state, args.at<Object>(0), @@ -1783,66 +1846,73 @@ // 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(JSFunction::cast(result), ic.target()->ic_in_loop()); + return CompileFunction(isolate, + JSFunction::cast(result), + ic.target()->ic_in_loop()); } // Used from ic-<arch>.cc. -MUST_USE_RESULT MaybeObject* KeyedCallIC_Miss(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 2); - KeyedCallIC ic; + KeyedCallIC ic(isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Object* result; { MaybeObject* maybe_result = ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); if (!maybe_result->ToObject(&result)) return maybe_result; } if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { return result; } - return CompileFunction(JSFunction::cast(result), ic.target()->ic_in_loop()); + return CompileFunction(isolate, + JSFunction::cast(result), + ic.target()->ic_in_loop()); } // Used from ic-<arch>.cc. -MUST_USE_RESULT MaybeObject* LoadIC_Miss(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 2); - LoadIC ic; + LoadIC ic(isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); return ic.Load(state, args.at<Object>(0), args.at<String>(1)); } // Used from ic-<arch>.cc -MUST_USE_RESULT MaybeObject* KeyedLoadIC_Miss(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 2); - KeyedLoadIC ic; + KeyedLoadIC ic(isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); } // Used from ic-<arch>.cc. -MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 3); - StoreIC ic; + StoreIC ic(isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); - return ic.Store(state, extra_ic_state, args.at<Object>(0), - args.at<String>(1), args.at<Object>(2)); + return ic.Store(state, + static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), + args.at<Object>(0), + args.at<String>(1), + args.at<Object>(2)); } -MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { NoHandleAllocation nha; ASSERT(args.length() == 2); JSObject* receiver = JSObject::cast(args[0]); Object* len = args[1]; @@ -1859,11 +1929,11 @@ // Extend storage is called in a store inline cache when // it is necessary to extend the properties array of a // JSObject. -MUST_USE_RESULT MaybeObject* SharedStoreIC_ExtendStorage(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) { NoHandleAllocation na; ASSERT(args.length() == 3); // Convert the parameters JSObject* object = JSObject::cast(args[0]); @@ -1893,16 +1963,20 @@ return value; } // Used from ic-<arch>.cc. -MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 3); - KeyedStoreIC ic; + KeyedStoreIC ic(isolate); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); - return ic.Store(state, args.at<Object>(0), args.at<Object>(1), + Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); + return ic.Store(state, + static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), + args.at<Object>(0), + args.at<Object>(1), args.at<Object>(2)); } void BinaryOpIC::patch(Code* code) { @@ -1962,35 +2036,36 @@ // defined in code-stubs-<arch>.cc Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info); -MUST_USE_RESULT MaybeObject* BinaryOp_Patch(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { ASSERT(args.length() == 5); - HandleScope scope; + HandleScope scope(isolate); Handle<Object> left = args.at<Object>(0); Handle<Object> right = args.at<Object>(1); int key = Smi::cast(args[2])->value(); Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value()); BinaryOpIC::TypeInfo previous_type = static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(*left, *right); Handle<Code> code = GetBinaryOpStub(key, type); if (!code.is_null()) { - BinaryOpIC ic; + BinaryOpIC ic(isolate); ic.patch(*code); if (FLAG_trace_ic) { PrintF("[BinaryOpIC (%s->%s)#%s]\n", BinaryOpIC::GetName(previous_type), BinaryOpIC::GetName(type), Token::Name(op)); } } - Handle<JSBuiltinsObject> builtins = Top::builtins(); + Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( + isolate->thread_local_top()->context_->builtins(), isolate); Object* builtin = NULL; // Initialization calms down the compiler. switch (op) { case Token::ADD: builtin = builtins->javascript_builtin(Builtins::ADD); break; @@ -2026,11 +2101,12 @@ break; default: UNREACHABLE(); } - Handle<JSFunction> builtin_function(JSFunction::cast(builtin)); + Handle<JSFunction> builtin_function(JSFunction::cast(builtin), + isolate); bool caught_exception; Object** builtin_args[] = { right.location() }; Handle<Object> result = Execution::Call(builtin_function, left, @@ -2053,10 +2129,11 @@ switch (type_info) { case UNINITIALIZED: return "Uninitialized"; case SMI: return "SMI"; case INT32: return "Int32s"; case HEAP_NUMBER: return "HeapNumbers"; + case ODDBALL: return "Oddball"; case STRING: return "Strings"; case GENERIC: return "Generic"; default: return "Invalid"; } } @@ -2067,10 +2144,11 @@ case UNINITIALIZED: return ::v8::internal::UNINITIALIZED; case SMI: case INT32: case HEAP_NUMBER: + case ODDBALL: case STRING: return MONOMORPHIC; case GENERIC: return MEGAMORPHIC; } @@ -2114,10 +2192,14 @@ // Patching for fast string ADD makes sense even if only one of the // arguments is a string. return STRING; } + // Check for oddball objects. + if (left->IsUndefined() && right->IsNumber()) return ODDBALL; + if (left->IsNumber() && right->IsUndefined()) return ODDBALL; + return GENERIC; } // defined in code-stubs-<arch>.cc @@ -2125,14 +2207,14 @@ Handle<Code> GetTypeRecordingBinaryOpStub(int key, TRBinaryOpIC::TypeInfo type_info, TRBinaryOpIC::TypeInfo result_type); -MaybeObject* TypeRecordingBinaryOp_Patch(Arguments args) { +RUNTIME_FUNCTION(MaybeObject*, TypeRecordingBinaryOp_Patch) { ASSERT(args.length() == 5); - HandleScope scope; + HandleScope scope(isolate); Handle<Object> left = args.at<Object>(0); Handle<Object> right = args.at<Object>(1); int key = Smi::cast(args[2])->value(); Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value()); TRBinaryOpIC::TypeInfo previous_type = @@ -2170,20 +2252,21 @@ TRBinaryOpIC::GetName(previous_type), TRBinaryOpIC::GetName(type), TRBinaryOpIC::GetName(result_type), Token::Name(op)); } - TRBinaryOpIC ic; + TRBinaryOpIC ic(isolate); ic.patch(*code); // Activate inlined smi code. if (previous_type == TRBinaryOpIC::UNINITIALIZED) { PatchInlinedSmiCode(ic.address()); } } - Handle<JSBuiltinsObject> builtins = Top::builtins(); + Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( + isolate->thread_local_top()->context_->builtins(), isolate); Object* builtin = NULL; // Initialization calms down the compiler. switch (op) { case Token::ADD: builtin = builtins->javascript_builtin(Builtins::ADD); break; @@ -2219,11 +2302,11 @@ break; default: UNREACHABLE(); } - Handle<JSFunction> builtin_function(JSFunction::cast(builtin)); + Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); bool caught_exception; Object** builtin_args[] = { right.location() }; Handle<Object> result = Execution::Call(builtin_function, left, @@ -2279,19 +2362,19 @@ return GENERIC; } // Used from ic_<arch>.cc. -Code* CompareIC_Miss(Arguments args) { +RUNTIME_FUNCTION(Code*, CompareIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 3); - CompareIC ic(static_cast<Token::Value>(Smi::cast(args[2])->value())); + CompareIC ic(isolate, static_cast<Token::Value>(Smi::cast(args[2])->value())); ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); return ic.target(); } -static Address IC_utilities[] = { +static const Address IC_utilities[] = { #define ADDR(name) FUNCTION_ADDR(name), IC_UTIL_LIST(ADDR) NULL #undef ADDR };