From e3792a6830b934c7c39a383b58ff6d29ef212bfa Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Thu, 20 Oct 2011 17:08:53 +0000 Subject: [PATCH] Handlify the stub cache lookup and patching for CallIC and KeyedCallIC. R=ulan@chromium.org,vegorov@chromium.org BUG= TEST= Review URL: http://codereview.chromium.org/8357010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9729 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/macro-assembler-arm.cc | 18 +- src/arm/stub-cache-arm.cc | 38 +- src/debug.cc | 10 +- src/ia32/macro-assembler-ia32.cc | 17 +- src/ia32/stub-cache-ia32.cc | 50 +- src/ic.cc | 217 +++------ src/ic.h | 12 +- src/objects.cc | 4 +- src/objects.h | 3 +- src/stub-cache.cc | 777 +++++++++++++++---------------- src/stub-cache.h | 227 +++++---- src/x64/macro-assembler-x64.cc | 25 +- src/x64/stub-cache-x64.cc | 45 +- test/cctest/test-debug.cc | 11 +- 14 files changed, 663 insertions(+), 791 deletions(-) diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index ab848c0df9..0ae8c26a74 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1101,24 +1101,16 @@ void MacroAssembler::InvokeFunction(JSFunction* function, // You can't call a function without a valid frame. ASSERT(flag == JUMP_FUNCTION || has_frame()); - ASSERT(function->is_compiled()); - // Get the function and setup the context. mov(r1, Operand(Handle(function))); ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); - // Invoke the cached code. - Handle code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); - InvokeCode(r3, expected, actual, flag, NullCallWrapper(), call_kind); - } else { - InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag, call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); + InvokeCode(r3, expected, actual, flag, NullCallWrapper(), call_kind); } diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 5f2374c08e..ce9eefadad 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -1480,9 +1480,9 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, MaybeObject* CallStubCompiler::GenerateMissBranch() { MaybeObject* maybe_obj = - isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), - kind_, - extra_ic_state_); + isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(), + kind_, + extra_state_); Object* obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ Jump(Handle(Code::cast(obj)), RelocInfo::CODE_TARGET); @@ -1513,7 +1513,7 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss); GenerateFastPropertyLoad(masm(), r1, reg, holder, index); - GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_); + GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_); // Handle call cache miss. __ bind(&miss); @@ -1831,7 +1831,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } @@ -1917,7 +1917,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } @@ -2474,7 +2474,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, UNREACHABLE(); } - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind); @@ -2510,7 +2510,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Get the receiver from the stack. __ ldr(r1, MemOperand(sp, argc * kPointerSize)); - CallInterceptorCompiler compiler(this, arguments(), r2, extra_ic_state_); + CallInterceptorCompiler compiler(this, arguments(), r2, extra_state_); MaybeObject* result = compiler.Compile(masm(), object, holder, @@ -2530,7 +2530,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Restore receiver. __ ldr(r0, MemOperand(sp, argc * kPointerSize)); - GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_); + GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_); // Handle call cache miss. __ bind(&miss); @@ -2585,23 +2585,17 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, // Jump to the cached code (tail call). Counters* counters = masm()->isolate()->counters(); __ IncrementCounter(counters->call_global_inline(), 1, r3, r4); - ASSERT(function->is_compiled()); Handle code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); - __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } else { - __ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET, - JUMP_FUNCTION, call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); + __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION, + NullCallWrapper(), call_kind); // Handle call cache miss. __ bind(&miss); diff --git a/src/debug.cc b/src/debug.cc index 492b617526..dc9f2974f7 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -87,19 +87,13 @@ static void PrintLn(v8::Local value) { static Handle ComputeCallDebugBreak(int argc, Code::Kind kind) { Isolate* isolate = Isolate::Current(); - CALL_HEAP_FUNCTION( - isolate, - isolate->stub_cache()->ComputeCallDebugBreak(argc, kind), - Code); + return isolate->stub_cache()->ComputeCallDebugBreak(argc, kind); } static Handle ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) { Isolate* isolate = Isolate::Current(); - CALL_HEAP_FUNCTION( - isolate, - isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind), - Code); + return isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind); } diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index fac2a02682..dd1ace91a7 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -2087,23 +2087,16 @@ void MacroAssembler::InvokeFunction(JSFunction* function, // You can't call a function without a valid frame. ASSERT(flag == JUMP_FUNCTION || has_frame()); - ASSERT(function->is_compiled()); // Get the function and setup the context. mov(edi, Immediate(Handle(function))); mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ParameterCount expected(function->shared()->formal_parameter_count()); - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), - expected, actual, flag, call_wrapper, call_kind); - } else { - Handle code(function->code()); - InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, - flag, call_wrapper, call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), + expected, actual, flag, call_wrapper, call_kind); } diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 1d16525152..139d7f5b5b 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -486,11 +486,11 @@ class CallInterceptorCompiler BASE_EMBEDDED { CallInterceptorCompiler(StubCompiler* stub_compiler, const ParameterCount& arguments, Register name, - Code::ExtraICState extra_ic_state) + Code::ExtraICState extra_state) : stub_compiler_(stub_compiler), arguments_(arguments), name_(name), - extra_ic_state_(extra_ic_state) {} + extra_state_(extra_state) {} MaybeObject* Compile(MacroAssembler* masm, JSObject* object, @@ -614,7 +614,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { GenerateFastApiCall(masm, optimization, arguments_.immediate()); if (result->IsFailure()) return result; } else { - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(optimization.constant_function(), arguments_, @@ -700,7 +700,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { StubCompiler* stub_compiler_; const ParameterCount& arguments_; Register name_; - Code::ExtraICState extra_ic_state_; + Code::ExtraICState extra_state_; }; @@ -1337,9 +1337,9 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, MaybeObject* CallStubCompiler::GenerateMissBranch() { MaybeObject* maybe_obj = - isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), - kind_, - extra_ic_state_); + isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(), + kind_, + extra_state_); Object* obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ jmp(Handle(Code::cast(obj)), RelocInfo::CODE_TARGET); @@ -1389,7 +1389,7 @@ MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField( } // Invoke the function. - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, @@ -1700,7 +1700,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } @@ -1786,7 +1786,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } @@ -1908,7 +1908,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -2339,7 +2339,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant( UNREACHABLE(); } - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -2378,7 +2378,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Get the receiver from the stack. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - CallInterceptorCompiler compiler(this, arguments(), ecx, extra_ic_state_); + CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_); MaybeObject* result = compiler.Compile(masm(), object, holder, @@ -2408,7 +2408,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Invoke the function. __ mov(edi, eax); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, @@ -2470,24 +2470,16 @@ MaybeObject* CallStubCompiler::CompileCallGlobal( // Jump to the cached code (tail call). Counters* counters = isolate()->counters(); __ IncrementCounter(counters->call_global_inline(), 1); - ASSERT(function->is_compiled()); ParameterCount expected(function->shared()->formal_parameter_count()); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), - expected, arguments(), JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } else { - Handle code(function->code()); - __ InvokeCode(code, expected, arguments(), - RelocInfo::CODE_TARGET, JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), + expected, arguments(), JUMP_FUNCTION, + NullCallWrapper(), call_kind); // Handle call cache miss. __ bind(&miss); diff --git a/src/ic.cc b/src/ic.cc index 1ad61222cc..5f779b1c94 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -100,7 +100,11 @@ void IC::TraceIC(const char* type, 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) { @@ -578,89 +582,57 @@ bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, } -MaybeObject* CallICBase::ComputeMonomorphicStub( - LookupResult* lookup, - State state, - Code::ExtraICState extra_ic_state, - Handle object, - Handle name) { +Handle CallICBase::ComputeMonomorphicStub(LookupResult* lookup, + State state, + Code::ExtraICState extra_state, + Handle object, + Handle name) { int argc = target()->arguments_count(); - MaybeObject* maybe_code = NULL; + Handle 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 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::null(); Handle receiver = Handle::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 global = Handle::cast(holder); + Handle cell(global->GetPropertyCell(lookup)); + if (!cell->value()->IsJSFunction()) return Handle::null(); + Handle 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::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::null(); } - return maybe_code; } @@ -682,75 +654,57 @@ void CallICBase::UpdateCaches(LookupResult* lookup, // Compute the number of arguments. int argc = target()->arguments_count(); - MaybeObject* maybe_code = NULL; bool had_proto_failure = false; + Handle 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 cache_object = object->IsJSObject() + ? Handle::cast(object) + : Handle(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()); } @@ -774,25 +728,15 @@ MaybeObject* KeyedCallIC::LoadFunction(State state, isolate()->factory()->non_strict_arguments_elements_map(); if (object->IsJSObject() && Handle::cast(object)->elements()->map() == *map) { - MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments( + Handle code = isolate()->stub_cache()->ComputeCallArguments( argc, Code::KEYED_CALL_IC); - Code* code = NULL; - if (maybe_code->To(&code)) { - set_target(code); -#ifdef DEBUG - TraceIC("KeyedCallIC", key, state, target()); -#endif - } + set_target(*code); + TRACE_IC("KeyedCallIC", key, state, target()); } else if (!object->IsAccessCheckNeeded()) { - MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic( + Handle code = isolate()->stub_cache()->ComputeCallMegamorphic( argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); - Code* code; - if (maybe_code->To(&code)) { - set_target(code); -#ifdef DEBUG - TraceIC("KeyedCallIC", key, state, target()); -#endif - } + set_target(*code); + TRACE_IC("KeyedCallIC", key, state, target()); } } @@ -1023,9 +967,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup, isolate()->stub_cache()->Set(*name, receiver->map(), *code); } -#ifdef DEBUG - TraceIC("LoadIC", name, state, target()); -#endif + TRACE_IC("LoadIC", name, state, target()); } @@ -1096,9 +1038,7 @@ MaybeObject* KeyedLoadIC::Load(State state, string); ASSERT(!code.is_null()); set_target(*code); -#ifdef DEBUG - TraceIC("KeyedLoadIC", name, state, target()); -#endif // DEBUG + TRACE_IC("KeyedLoadIC", name, state, target()); return Smi::FromInt(string->length()); } @@ -1110,9 +1050,7 @@ MaybeObject* KeyedLoadIC::Load(State state, isolate()->stub_cache()->ComputeKeyedLoadArrayLength(name, array); ASSERT(!code.is_null()); set_target(*code); -#ifdef DEBUG - TraceIC("KeyedLoadIC", name, state, target()); -#endif // DEBUG + TRACE_IC("KeyedLoadIC", name, state, target()); return array->length(); } @@ -1126,9 +1064,7 @@ MaybeObject* KeyedLoadIC::Load(State state, name, function); ASSERT(!code.is_null()); set_target(*code); -#ifdef DEBUG - TraceIC("KeyedLoadIC", name, state, target()); -#endif // DEBUG + TRACE_IC("KeyedLoadIC", name, state, target()); return Accessors::FunctionGetPrototype(*object, 0); } } @@ -1198,9 +1134,7 @@ MaybeObject* KeyedLoadIC::Load(State state, 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); @@ -1273,9 +1207,7 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup, set_target(*megamorphic_stub()); } -#ifdef DEBUG - TraceIC("KeyedLoadIC", name, state, target()); -#endif + TRACE_IC("KeyedLoadIC", name, state, target()); } @@ -1390,9 +1322,7 @@ MaybeObject* StoreIC::Store(State state, : global_proxy_stub(); if (target() != *stub) { set_target(*stub); -#ifdef DEBUG - TraceIC("StoreIC", name, state, target()); -#endif + TRACE_IC("StoreIC", name, state, target()); } } @@ -1486,9 +1416,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, isolate()->stub_cache()->Set(*name, receiver->map(), *code); } -#ifdef DEBUG - TraceIC("StoreIC", name, state, target()); -#endif + TRACE_IC("StoreIC", name, state, target()); } @@ -1789,9 +1717,7 @@ MaybeObject* KeyedStoreIC::Store(State state, 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( @@ -1863,12 +1789,13 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, : *megamorphic_stub()); } -#ifdef DEBUG - TraceIC("KeyedStoreIC", name, state, target()); -#endif + TRACE_IC("KeyedStoreIC", name, state, target()); } +#undef TRACE_IC + + // ---------------------------------------------------------------------------- // Static IC stub generators. // diff --git a/src/ic.h b/src/ic.h index efef44a3b1..6e58eacd94 100644 --- a/src/ic.h +++ b/src/ic.h @@ -216,12 +216,12 @@ class CallICBase: public IC { Handle object, Code::ExtraICState* extra_ic_state); - MUST_USE_RESULT MaybeObject* ComputeMonomorphicStub( - LookupResult* lookup, - State state, - Code::ExtraICState extra_ic_state, - Handle object, - Handle name); + // Compute a monomorphic stub if possible, otherwise return a null handle. + Handle ComputeMonomorphicStub(LookupResult* lookup, + State state, + Code::ExtraICState extra_state, + Handle object, + Handle name); // Update the inline cache and the global stub cache based on the lookup // result. diff --git a/src/objects.cc b/src/objects.cc index 29ce51f36d..daaed525cc 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3246,10 +3246,10 @@ void NormalizedMapCache::Clear() { } -void JSObject::UpdateMapCodeCache(Isolate* isolate, - Handle object, +void JSObject::UpdateMapCodeCache(Handle object, Handle name, Handle code) { + Isolate* isolate = object->GetIsolate(); CALL_HEAP_FUNCTION_VOID(isolate, object->UpdateMapCodeCache(*name, *code)); } diff --git a/src/objects.h b/src/objects.h index 6c1d2698b5..21aa321f42 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1850,8 +1850,7 @@ class JSObject: public JSReceiver { // dictionary. Returns the backing after conversion. MUST_USE_RESULT MaybeObject* NormalizeElements(); - static void UpdateMapCodeCache(Isolate* isolate, - Handle object, + static void UpdateMapCodeCache(Handle object, Handle name, Handle code); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 7c0f8baa70..b1619b5752 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -147,7 +147,7 @@ Handle StubCache::ComputeLoadNonexistent(Handle name, compiler.CompileLoadNonexistent(cache_name, receiver, last); PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name)); GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, cache_name, code); + JSObject::UpdateMapCodeCache(receiver, cache_name, code); return code; } @@ -177,7 +177,7 @@ Handle StubCache::ComputeLoadField(Handle name, compiler.CompileLoadField(receiver, holder, field_index, name); PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -209,7 +209,7 @@ Handle StubCache::ComputeLoadCallback(Handle name, compiler.CompileLoadCallback(name, receiver, holder, callback); PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -240,7 +240,7 @@ Handle StubCache::ComputeLoadConstant(Handle name, compiler.CompileLoadConstant(receiver, holder, value, name); PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -268,7 +268,7 @@ Handle StubCache::ComputeLoadInterceptor(Handle name, compiler.CompileLoadInterceptor(receiver, holder, name); PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -304,7 +304,7 @@ Handle StubCache::ComputeLoadGlobal(Handle name, compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete); PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -334,7 +334,7 @@ Handle StubCache::ComputeKeyedLoadField(Handle name, compiler.CompileLoadField(name, receiver, holder, field_index); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -365,7 +365,7 @@ Handle StubCache::ComputeKeyedLoadConstant(Handle name, compiler.CompileLoadConstant(name, receiver, holder, value); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -394,7 +394,7 @@ Handle StubCache::ComputeKeyedLoadInterceptor(Handle name, Handle code = compiler.CompileLoadInterceptor(receiver, holder, name); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -427,7 +427,7 @@ Handle StubCache::ComputeKeyedLoadCallback( compiler.CompileLoadCallback(name, receiver, holder, callback); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -451,7 +451,7 @@ Handle StubCache::ComputeKeyedLoadArrayLength(Handle name, Handle code = compiler.CompileLoadArrayLength(name); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -502,7 +502,7 @@ Handle StubCache::ComputeKeyedLoadFunctionPrototype( Handle code = compiler.CompileLoadFunctionPrototype(name); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -511,14 +511,13 @@ Handle StoreStubCompiler::CompileStoreField(Handle object, int index, Handle transition, Handle name) { - CALL_HEAP_FUNCTION(isolate(), - (set_failure(NULL), - CompileStoreField( - *object, - index, - (transition.is_null() ? NULL : *transition), - *name)), - Code); + CALL_HEAP_FUNCTION( + isolate(), + (set_failure(NULL), + CompileStoreField(*object, index, + transition.is_null() ? NULL : *transition, + *name)), + Code); } @@ -538,7 +537,7 @@ Handle StubCache::ComputeStoreField(Handle name, compiler.CompileStoreField(receiver, field_index, transition, name); PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -640,7 +639,7 @@ Handle StubCache::ComputeStoreGlobal(Handle name, Handle code = compiler.CompileStoreGlobal(receiver, cell, name); PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -670,7 +669,7 @@ Handle StubCache::ComputeStoreCallback(Handle name, Handle code = compiler.CompileStoreCallback(receiver, callback, name); PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -696,7 +695,7 @@ Handle StubCache::ComputeStoreInterceptor(Handle name, Handle code = compiler.CompileStoreInterceptor(receiver, name); PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -704,14 +703,13 @@ Handle KeyedStoreStubCompiler::CompileStoreField(Handle object, int index, Handle transition, Handle name) { - CALL_HEAP_FUNCTION(isolate(), - (set_failure(NULL), - CompileStoreField( - *object, - index, - (transition.is_null() ? NULL : *transition), - *name)), - Code); + CALL_HEAP_FUNCTION( + isolate(), + (set_failure(NULL), + CompileStoreField(*object, index, + transition.is_null() ? NULL : *transition, + *name)), + Code); } Handle StubCache::ComputeKeyedStoreField(Handle name, @@ -730,7 +728,7 @@ Handle StubCache::ComputeKeyedStoreField(Handle name, compiler.CompileStoreField(receiver, field_index, transition, name); PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name)); GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code)); - JSObject::UpdateMapCodeCache(isolate_, receiver, name, code); + JSObject::UpdateMapCodeCache(receiver, name, code); return code; } @@ -738,17 +736,30 @@ Handle StubCache::ComputeKeyedStoreField(Handle name, #define CALL_LOGGER_TAG(kind, type) \ (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type) -MaybeObject* StubCache::ComputeCallConstant(int argc, +Handle CallStubCompiler::CompileCallConstant(Handle object, + Handle holder, + Handle function, + Handle name, + CheckType check) { + CALL_HEAP_FUNCTION( + isolate(), + (set_failure(NULL), + CompileCallConstant(*object, *holder, *function, *name, check)), + Code); +} + + +Handle StubCache::ComputeCallConstant(int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state, - String* name, - Object* object, - JSObject* holder, - JSFunction* function) { + Code::ExtraICState extra_state, + Handle name, + Handle object, + Handle holder, + Handle function) { // Compute the check type and the map. InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(object, holder); - JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder); + IC::GetCodeCacheForObject(*object, *holder); + Handle map_holder(IC::GetCodeCacheHolder(*object, cache_holder)); // Compute check type based on receiver/holder. CheckType check = RECEIVER_MAP_CHECK; @@ -760,56 +771,47 @@ MaybeObject* StubCache::ComputeCallConstant(int argc, check = BOOLEAN_CHECK; } - Code::Flags flags = Code::ComputeMonomorphicFlags(kind, - CONSTANT_FUNCTION, - extra_ic_state, - cache_holder, - argc); - Object* code = map_holder->map()->FindInCodeCache(name, flags); - if (code->IsUndefined()) { - // If the function hasn't been compiled yet, we cannot do it now - // because it may cause GC. To avoid this issue, we return an - // internal error which will make sure we do not update any - // caches. - if (!function->is_compiled()) return Failure::InternalError(); - // Compile the stub - only create stubs for fully compiled functions. - HandleScope scope(isolate_); - CallStubCompiler compiler(isolate_, - argc, - kind, - extra_ic_state, - cache_holder); - { MaybeObject* maybe_code = - compiler.CompileCallConstant(object, holder, function, name, check); - if (!maybe_code->ToObject(&code)) return maybe_code; - } - Code::cast(code)->set_check_type(check); - ASSERT_EQ(flags, Code::cast(code)->flags()); - PROFILE(isolate_, - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), - Code::cast(code), name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); - Object* result; - { MaybeObject* maybe_result = - map_holder->UpdateMapCodeCache(name, Code::cast(code)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - } + Code::Flags flags = + Code::ComputeMonomorphicFlags(kind, CONSTANT_FUNCTION, extra_state, + cache_holder, argc); + Handle probe(map_holder->map()->FindInCodeCache(*name, flags)); + if (probe->IsCode()) return Handle::cast(probe); + + CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); + Handle code = + compiler.CompileCallConstant(object, holder, function, name, check); + code->set_check_type(check); + ASSERT_EQ(flags, code->flags()); + PROFILE(isolate_, + CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); + JSObject::UpdateMapCodeCache(map_holder, name, code); return code; } -MaybeObject* StubCache::ComputeCallField(int argc, +Handle CallStubCompiler::CompileCallField(Handle object, + Handle holder, + int index, + Handle name) { + CALL_HEAP_FUNCTION( + isolate(), + (set_failure(NULL), CompileCallField(*object, *holder, index, *name)), + Code); +} + + +Handle StubCache::ComputeCallField(int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state, - String* name, - Object* object, - JSObject* holder, + Code::ExtraICState extra_state, + Handle name, + Handle object, + Handle holder, int index) { // Compute the check type and the map. InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(object, holder); - JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder); + IC::GetCodeCacheForObject(*object, *holder); + Handle map_holder(IC::GetCodeCacheHolder(*object, cache_holder)); // TODO(1233596): We cannot do receiver map check for non-JS objects // because they may be represented as immediates without a @@ -818,52 +820,45 @@ MaybeObject* StubCache::ComputeCallField(int argc, object = holder; } - Code::Flags flags = Code::ComputeMonomorphicFlags(kind, - FIELD, - extra_ic_state, - cache_holder, - argc); - Object* code = map_holder->map()->FindInCodeCache(name, flags); - if (code->IsUndefined()) { - HandleScope scope(isolate_); - CallStubCompiler compiler(isolate_, - argc, - kind, - extra_ic_state, - cache_holder); - { MaybeObject* maybe_code = - compiler.CompileCallField(JSObject::cast(object), - holder, - index, - name); - if (!maybe_code->ToObject(&code)) return maybe_code; - } - ASSERT_EQ(flags, Code::cast(code)->flags()); - PROFILE(isolate_, - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), - Code::cast(code), name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); - Object* result; - { MaybeObject* maybe_result = - map_holder->UpdateMapCodeCache(name, Code::cast(code)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - } + Code::Flags flags = + Code::ComputeMonomorphicFlags(kind, FIELD, extra_state, + cache_holder, argc); + Handle probe(map_holder->map()->FindInCodeCache(*name, flags)); + if (probe->IsCode()) return Handle::cast(probe); + + CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); + Handle code = + compiler.CompileCallField(Handle::cast(object), + holder, index, name); + ASSERT_EQ(flags, code->flags()); + PROFILE(isolate_, + CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); + JSObject::UpdateMapCodeCache(map_holder, name, code); return code; } -MaybeObject* StubCache::ComputeCallInterceptor( - int argc, - Code::Kind kind, - Code::ExtraICState extra_ic_state, - String* name, - Object* object, - JSObject* holder) { +Handle CallStubCompiler::CompileCallInterceptor(Handle object, + Handle holder, + Handle name) { + CALL_HEAP_FUNCTION( + isolate(), + (set_failure(NULL), CompileCallInterceptor(*object, *holder, *name)), + Code); +} + + +Handle StubCache::ComputeCallInterceptor(int argc, + Code::Kind kind, + Code::ExtraICState extra_state, + Handle name, + Handle object, + Handle holder) { // Compute the check type and the map. InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(object, holder); - JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder); + IC::GetCodeCacheForObject(*object, *holder); + Handle map_holder(IC::GetCodeCacheHolder(*object, cache_holder)); // TODO(1233596): We cannot do receiver map check for non-JS objects // because they may be represented as immediates without a @@ -872,144 +867,75 @@ MaybeObject* StubCache::ComputeCallInterceptor( object = holder; } - Code::Flags flags = Code::ComputeMonomorphicFlags(kind, - INTERCEPTOR, - extra_ic_state, - cache_holder, - argc); - Object* code = map_holder->map()->FindInCodeCache(name, flags); - if (code->IsUndefined()) { - HandleScope scope(isolate()); - CallStubCompiler compiler(isolate(), - argc, - kind, - extra_ic_state, - cache_holder); - { MaybeObject* maybe_code = - compiler.CompileCallInterceptor(JSObject::cast(object), holder, name); - if (!maybe_code->ToObject(&code)) return maybe_code; - } - ASSERT_EQ(flags, Code::cast(code)->flags()); - PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), - Code::cast(code), name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); - Object* result; - { MaybeObject* maybe_result = - map_holder->UpdateMapCodeCache(name, Code::cast(code)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - } + Code::Flags flags = + Code::ComputeMonomorphicFlags(kind, INTERCEPTOR, extra_state, + cache_holder, argc); + Handle probe(map_holder->map()->FindInCodeCache(*name, flags)); + if (probe->IsCode()) return Handle::cast(probe); + + CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); + Handle code = + compiler.CompileCallInterceptor(Handle::cast(object), + holder, name); + ASSERT_EQ(flags, code->flags()); + PROFILE(isolate(), + CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); + JSObject::UpdateMapCodeCache(map_holder, name, code); return code; } -MaybeObject* StubCache::ComputeCallNormal(int argc, - Code::Kind kind, - Code::ExtraICState extra_ic_state, - String* name, - JSObject* receiver) { - Object* code; - { MaybeObject* maybe_code = ComputeCallNormal(argc, kind, extra_ic_state); - if (!maybe_code->ToObject(&code)) return maybe_code; - } - return code; +Handle CallStubCompiler::CompileCallGlobal( + Handle object, + Handle holder, + Handle cell, + Handle function, + Handle name) { + CALL_HEAP_FUNCTION( + isolate(), + (set_failure(NULL), + CompileCallGlobal(*object, *holder, *cell, *function, *name)), + Code); } -MaybeObject* StubCache::ComputeCallGlobal(int argc, +Handle StubCache::ComputeCallGlobal(int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state, - String* name, - JSObject* receiver, - GlobalObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function) { + Code::ExtraICState extra_state, + Handle name, + Handle receiver, + Handle holder, + Handle cell, + Handle function) { InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(receiver, holder); - JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder); - Code::Flags flags = Code::ComputeMonomorphicFlags(kind, - NORMAL, - extra_ic_state, - cache_holder, - argc); - Object* code = map_holder->map()->FindInCodeCache(name, flags); - if (code->IsUndefined()) { - // If the function hasn't been compiled yet, we cannot do it now - // because it may cause GC. To avoid this issue, we return an - // internal error which will make sure we do not update any - // caches. - if (!function->is_compiled()) return Failure::InternalError(); - HandleScope scope(isolate()); - CallStubCompiler compiler(isolate(), - argc, - kind, - extra_ic_state, - cache_holder); - { MaybeObject* maybe_code = - compiler.CompileCallGlobal(receiver, holder, cell, function, name); - if (!maybe_code->ToObject(&code)) return maybe_code; - } - ASSERT_EQ(flags, Code::cast(code)->flags()); - PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), - Code::cast(code), name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); - Object* result; - { MaybeObject* maybe_result = - map_holder->UpdateMapCodeCache(name, Code::cast(code)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - } + IC::GetCodeCacheForObject(*receiver, *holder); + Handle map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder)); + Code::Flags flags = + Code::ComputeMonomorphicFlags(kind, NORMAL, extra_state, + cache_holder, argc); + Handle probe(map_holder->map()->FindInCodeCache(*name, flags)); + if (probe->IsCode()) return Handle::cast(probe); + + CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); + Handle code = + compiler.CompileCallGlobal(receiver, holder, cell, function, name); + ASSERT_EQ(flags, code->flags()); + PROFILE(isolate(), + CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); + JSObject::UpdateMapCodeCache(map_holder, name, code); return code; } -static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) { - // Use raw_unchecked... so we don't get assert failures during GC. - NumberDictionary* dictionary = - isolate->heap()->raw_unchecked_non_monomorphic_cache(); - int entry = dictionary->FindEntry(isolate, flags); - if (entry != -1) return dictionary->ValueAt(entry); - return isolate->heap()->raw_unchecked_undefined_value(); -} - - -MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate, - Code::Flags flags) { - Heap* heap = isolate->heap(); - Object* probe = GetProbeValue(isolate, flags); - if (probe != heap->undefined_value()) return probe; - // Seed the cache with an undefined value to make sure that any - // generated code object can always be inserted into the cache - // without causing allocation failures. - Object* result; - { MaybeObject* maybe_result = - heap->non_monomorphic_cache()->AtNumberPut(flags, - heap->undefined_value()); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result)); - return probe; -} - - -static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) { - Object* code; - if (maybe_code->ToObject(&code)) { - if (code->IsCode()) { - Heap* heap = isolate->heap(); - int entry = heap->non_monomorphic_cache()->FindEntry( - Code::cast(code)->flags()); - // The entry must be present see comment in ProbeCache. - ASSERT(entry != -1); - ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) == - heap->undefined_value()); - heap->non_monomorphic_cache()->ValueAtPut(entry, code); - CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code); - } - } - return maybe_code; +static void FillCache(Isolate* isolate, Handle code) { + Handle dictionary = + NumberDictionarySet(isolate->factory()->non_monomorphic_cache(), + code->flags(), + code, + PropertyDetails(NONE, NORMAL)); + isolate->heap()->public_set_non_monomorphic_cache(*dictionary); } @@ -1019,196 +945,197 @@ Code* StubCache::FindCallInitialize(int argc, Code::ExtraICState extra_state = CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); - Code::Flags flags = Code::ComputeFlags(kind, - UNINITIALIZED, - extra_state, - NORMAL, - argc); - Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked(); - ASSERT(result != heap()->undefined_value()); + Code::Flags flags = + Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc); + + // Use raw_unchecked... so we don't get assert failures during GC. + NumberDictionary* dictionary = + isolate()->heap()->raw_unchecked_non_monomorphic_cache(); + int entry = dictionary->FindEntry(isolate(), flags); + ASSERT(entry != -1); + Object* code = dictionary->ValueAt(entry); // This might be called during the marking phase of the collector // hence the unchecked cast. - return reinterpret_cast(result); + return reinterpret_cast(code); } -MaybeObject* StubCache::ComputeCallInitialize(int argc, +Handle StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind) { Code::ExtraICState extra_state = CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); - Code::Flags flags = Code::ComputeFlags(kind, - UNINITIALIZED, - extra_state, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::Flags flags = + Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallInitialize(flags)); + Handle code = compiler.CompileCallInitialize(flags); + FillCache(isolate_, code); + return code; } -Handle StubCache::ComputeCallInitialize(int argc, - RelocInfo::Mode mode) { - CALL_HEAP_FUNCTION(isolate_, - ComputeCallInitialize(argc, mode, Code::CALL_IC), - Code); +Handle StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) { + return ComputeCallInitialize(argc, mode, Code::CALL_IC); } Handle StubCache::ComputeKeyedCallInitialize(int argc) { - CALL_HEAP_FUNCTION( - isolate_, - ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, Code::KEYED_CALL_IC), - Code); + return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, Code::KEYED_CALL_IC); } -MaybeObject* StubCache::ComputeCallPreMonomorphic( +Handle StubCache::ComputeCallPreMonomorphic( int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state) { - Code::Flags flags = Code::ComputeFlags(kind, - PREMONOMORPHIC, - extra_ic_state, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::ExtraICState extra_state) { + Code::Flags flags = + Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags)); + Handle code = compiler.CompileCallPreMonomorphic(flags); + FillCache(isolate_, code); + return code; } -MaybeObject* StubCache::ComputeCallNormal(int argc, +Handle StubCache::ComputeCallNormal(int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state) { - Code::Flags flags = Code::ComputeFlags(kind, - MONOMORPHIC, - extra_ic_state, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::ExtraICState extra_state) { + Code::Flags flags = + Code::ComputeFlags(kind, MONOMORPHIC, extra_state, NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallNormal(flags)); + Handle code = compiler.CompileCallNormal(flags); + FillCache(isolate_, code); + return code; } -MaybeObject* StubCache::ComputeCallArguments(int argc, Code::Kind kind) { +Handle StubCache::ComputeCallArguments(int argc, Code::Kind kind) { ASSERT(kind == Code::KEYED_CALL_IC); - Code::Flags flags = Code::ComputeFlags(kind, - MEGAMORPHIC, - Code::kNoExtraICState, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::Flags flags = + Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState, + NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallArguments(flags)); + Handle code = compiler.CompileCallArguments(flags); + FillCache(isolate_, code); + return code; } -MaybeObject* StubCache::ComputeCallMegamorphic( +Handle StubCache::ComputeCallMegamorphic( int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state) { - Code::Flags flags = Code::ComputeFlags(kind, - MEGAMORPHIC, - extra_ic_state, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::ExtraICState extra_state) { + Code::Flags flags = + Code::ComputeFlags(kind, MEGAMORPHIC, extra_state, + NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallMegamorphic(flags)); + Handle code = compiler.CompileCallMegamorphic(flags); + FillCache(isolate_, code); + return code; } -MaybeObject* StubCache::ComputeCallMiss(int argc, +Handle StubCache::ComputeCallMiss(int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state) { + Code::ExtraICState extra_state) { // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs // and monomorphic stubs are not mixed up together in the stub cache. - Code::Flags flags = Code::ComputeFlags(kind, - MONOMORPHIC_PROTOTYPE_FAILURE, - extra_ic_state, - NORMAL, - argc, - OWN_MAP); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::Flags flags = + Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state, + NORMAL, argc, OWN_MAP); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallMiss(flags)); + Handle code = compiler.CompileCallMiss(flags); + FillCache(isolate_, code); + return code; +} + + +// The CallStubCompiler needs a version of ComputeCallMiss that does not +// perform GC. This function is temporary, because the stub cache but not +// yet the stub compiler uses handles. +MaybeObject* StubCache::TryComputeCallMiss(int argc, + Code::Kind kind, + Code::ExtraICState extra_state) { + Code::Flags flags = + Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state, + NORMAL, argc, OWN_MAP); + NumberDictionary* cache = isolate_->heap()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return cache->ValueAt(entry); + + StubCompiler compiler(isolate_); + Code* code = NULL; + MaybeObject* maybe_code = compiler.TryCompileCallMiss(flags); + if (!maybe_code->To(&code)) return maybe_code; + + NumberDictionary* new_cache = NULL; + MaybeObject* maybe_new_cache = cache->AtNumberPut(flags, code); + if (!maybe_new_cache->To(&new_cache)) return maybe_new_cache; + isolate_->heap()->public_set_non_monomorphic_cache(new_cache); + + return code; } #ifdef ENABLE_DEBUGGER_SUPPORT -MaybeObject* StubCache::ComputeCallDebugBreak( - int argc, - Code::Kind kind) { +Handle StubCache::ComputeCallDebugBreak(int argc, + Code::Kind kind) { // Extra IC state is irrelevant for debug break ICs. They jump to // the actual call ic to carry out the work. - Code::Flags flags = Code::ComputeFlags(kind, - DEBUG_BREAK, - Code::kNoExtraICState, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::Flags flags = + Code::ComputeFlags(kind, DEBUG_BREAK, Code::kNoExtraICState, + NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallDebugBreak(flags)); + Handle code = compiler.CompileCallDebugBreak(flags); + FillCache(isolate_, code); + return code; } -MaybeObject* StubCache::ComputeCallDebugPrepareStepIn( - int argc, - Code::Kind kind) { +Handle StubCache::ComputeCallDebugPrepareStepIn(int argc, + Code::Kind kind) { // Extra IC state is irrelevant for debug break ICs. They jump to // the actual call ic to carry out the work. - Code::Flags flags = Code::ComputeFlags(kind, - DEBUG_PREPARE_STEP_IN, - Code::kNoExtraICState, - NORMAL, - argc); - Object* probe; - { MaybeObject* maybe_probe = ProbeCache(isolate_, flags); - if (!maybe_probe->ToObject(&probe)) return maybe_probe; - } - if (!probe->IsUndefined()) return probe; - HandleScope scope(isolate_); + Code::Flags flags = + Code::ComputeFlags(kind, DEBUG_PREPARE_STEP_IN, Code::kNoExtraICState, + NORMAL, argc); + Handle cache = isolate_->factory()->non_monomorphic_cache(); + int entry = cache->FindEntry(isolate_, flags); + if (entry != -1) return Handle(Code::cast(cache->ValueAt(entry))); + StubCompiler compiler(isolate_); - return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags)); + Handle code = compiler.CompileCallDebugPrepareStepIn(flags); + FillCache(isolate_, code); + return code; } #endif @@ -1473,13 +1400,20 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) { } -MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) { +Handle StubCompiler::CompileCallInitialize(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallInitialize(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallInitialize(Code::Flags flags) { HandleScope scope(isolate()); int argc = Code::ExtractArgumentsCountFromFlags(flags); Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags); + Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); if (kind == Code::CALL_IC) { - CallIC::GenerateInitialize(masm(), argc, extra_ic_state); + CallIC::GenerateInitialize(masm(), argc, extra_state); } else { KeyedCallIC::GenerateInitialize(masm(), argc); } @@ -1499,15 +1433,22 @@ MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) { } -MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { +Handle StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallPreMonomorphic(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallPreMonomorphic(Code::Flags flags) { HandleScope scope(isolate()); int argc = Code::ExtractArgumentsCountFromFlags(flags); // The code of the PreMonomorphic stub is the same as the code // of the Initialized stub. They just differ on the code object flags. Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags); + Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); if (kind == Code::CALL_IC) { - CallIC::GenerateInitialize(masm(), argc, extra_ic_state); + CallIC::GenerateInitialize(masm(), argc, extra_state); } else { KeyedCallIC::GenerateInitialize(masm(), argc); } @@ -1527,7 +1468,14 @@ MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { } -MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) { +Handle StubCompiler::CompileCallNormal(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallNormal(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallNormal(Code::Flags flags) { HandleScope scope(isolate()); int argc = Code::ExtractArgumentsCountFromFlags(flags); Code::Kind kind = Code::ExtractKindFromFlags(flags); @@ -1554,13 +1502,20 @@ MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) { } -MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) { +Handle StubCompiler::CompileCallMegamorphic(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallMegamorphic(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallMegamorphic(Code::Flags flags) { HandleScope scope(isolate()); int argc = Code::ExtractArgumentsCountFromFlags(flags); Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags); + Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); if (kind == Code::CALL_IC) { - CallIC::GenerateMegamorphic(masm(), argc, extra_ic_state); + CallIC::GenerateMegamorphic(masm(), argc, extra_state); } else { KeyedCallIC::GenerateMegamorphic(masm(), argc); } @@ -1580,7 +1535,14 @@ MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) { } -MaybeObject* StubCompiler::CompileCallArguments(Code::Flags flags) { +Handle StubCompiler::CompileCallArguments(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallArguments(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallArguments(Code::Flags flags) { HandleScope scope(isolate()); int argc = Code::ExtractArgumentsCountFromFlags(flags); KeyedCallIC::GenerateNonStrictArguments(masm(), argc); @@ -1600,13 +1562,20 @@ MaybeObject* StubCompiler::CompileCallArguments(Code::Flags flags) { } -MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) { +Handle StubCompiler::CompileCallMiss(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallMiss(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallMiss(Code::Flags flags) { HandleScope scope(isolate()); int argc = Code::ExtractArgumentsCountFromFlags(flags); Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags); + Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); if (kind == Code::CALL_IC) { - CallIC::GenerateMiss(masm(), argc, extra_ic_state); + CallIC::GenerateMiss(masm(), argc, extra_state); } else { KeyedCallIC::GenerateMiss(masm(), argc); } @@ -1626,7 +1595,14 @@ MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) { #ifdef ENABLE_DEBUGGER_SUPPORT -MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) { +Handle StubCompiler::CompileCallDebugBreak(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallDebugBreak(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallDebugBreak(Code::Flags flags) { HandleScope scope(isolate()); Debug::GenerateCallICDebugBreak(masm()); Object* result; @@ -1645,7 +1621,14 @@ MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) { } -MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { +Handle StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { + CALL_HEAP_FUNCTION(isolate(), + (set_failure(NULL), TryCompileCallDebugPrepareStepIn(flags)), + Code); +} + + +MaybeObject* StubCompiler::TryCompileCallDebugPrepareStepIn(Code::Flags flags) { HandleScope scope(isolate()); // Use the same code for the the step in preparations as we do for // the miss case. @@ -1796,12 +1779,12 @@ void KeyedStoreStubCompiler::GenerateStoreDictionaryElement( CallStubCompiler::CallStubCompiler(Isolate* isolate, int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state, + Code::ExtraICState extra_state, InlineCacheHolderFlag cache_holder) : StubCompiler(isolate), arguments_(argc), kind_(kind), - extra_ic_state_(extra_ic_state), + extra_state_(extra_state), cache_holder_(cache_holder) { } @@ -1858,7 +1841,7 @@ MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) { int argc = arguments_.immediate(); Code::Flags flags = Code::ComputeMonomorphicFlags(kind_, type, - extra_ic_state_, + extra_state_, cache_holder_, argc); return GetCodeWithFlags(flags, name); diff --git a/src/stub-cache.h b/src/stub-cache.h index a6f40a789c..c1fffc6a7b 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -175,90 +175,73 @@ class StubCache { // --- - MUST_USE_RESULT MaybeObject* ComputeCallField( - int argc, - Code::Kind, - Code::ExtraICState extra_ic_state, - String* name, - Object* object, - JSObject* holder, - int index); + Handle ComputeCallField(int argc, + Code::Kind, + Code::ExtraICState extra_state, + Handle name, + Handle object, + Handle holder, + int index); - MUST_USE_RESULT MaybeObject* ComputeCallConstant( - int argc, - Code::Kind, - Code::ExtraICState extra_ic_state, - String* name, - Object* object, - JSObject* holder, - JSFunction* function); + Handle ComputeCallConstant(int argc, + Code::Kind, + Code::ExtraICState extra_state, + Handle name, + Handle object, + Handle holder, + Handle function); - MUST_USE_RESULT MaybeObject* ComputeCallNormal( - int argc, - Code::Kind, - Code::ExtraICState extra_ic_state, - String* name, - JSObject* receiver); + Handle ComputeCallInterceptor(int argc, + Code::Kind, + Code::ExtraICState extra_state, + Handle name, + Handle object, + Handle holder); - MUST_USE_RESULT MaybeObject* ComputeCallInterceptor( - int argc, - Code::Kind, - Code::ExtraICState extra_ic_state, - String* name, - Object* object, - JSObject* holder); - - MUST_USE_RESULT MaybeObject* ComputeCallGlobal( - int argc, - Code::Kind, - Code::ExtraICState extra_ic_state, - String* name, - JSObject* receiver, - GlobalObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function); + Handle ComputeCallGlobal(int argc, + Code::Kind, + Code::ExtraICState extra_state, + Handle name, + Handle receiver, + Handle holder, + Handle cell, + Handle function); // --- - MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc, - RelocInfo::Mode mode, - Code::Kind kind); - - Handle ComputeCallInitialize(int argc, - RelocInfo::Mode mode); + Handle ComputeCallInitialize(int argc, RelocInfo::Mode mode); Handle ComputeKeyedCallInitialize(int argc); - MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic( - int argc, - Code::Kind kind, - Code::ExtraICState extra_ic_state); + Handle ComputeCallPreMonomorphic(int argc, + Code::Kind kind, + Code::ExtraICState extra_state); - MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc, - Code::Kind kind, - Code::ExtraICState state); + Handle ComputeCallNormal(int argc, + Code::Kind kind, + Code::ExtraICState state); - MUST_USE_RESULT MaybeObject* ComputeCallArguments(int argc, - Code::Kind kind); + Handle ComputeCallArguments(int argc, Code::Kind kind); - MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc, - Code::Kind kind, - Code::ExtraICState state); + Handle ComputeCallMegamorphic(int argc, + Code::Kind kind, + Code::ExtraICState state); - MUST_USE_RESULT MaybeObject* ComputeCallMiss(int argc, - Code::Kind kind, - Code::ExtraICState state); + Handle ComputeCallMiss(int argc, + Code::Kind kind, + Code::ExtraICState state); + + MUST_USE_RESULT MaybeObject* TryComputeCallMiss(int argc, + Code::Kind kind, + Code::ExtraICState state); // Finds the Code object stored in the Heap::non_monomorphic_cache(). - MUST_USE_RESULT Code* FindCallInitialize(int argc, - RelocInfo::Mode mode, - Code::Kind kind); + Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind); #ifdef ENABLE_DEBUGGER_SUPPORT - MUST_USE_RESULT MaybeObject* ComputeCallDebugBreak(int argc, Code::Kind kind); + Handle ComputeCallDebugBreak(int argc, Code::Kind kind); - MUST_USE_RESULT MaybeObject* ComputeCallDebugPrepareStepIn(int argc, - Code::Kind kind); + Handle ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind); #endif // Update cache for entry hash(name, map). @@ -317,12 +300,9 @@ class StubCache { private: explicit StubCache(Isolate* isolate); - friend class Isolate; - friend class SCTableReference; - static const int kPrimaryTableSize = 2048; - static const int kSecondaryTableSize = 512; - Entry primary_[kPrimaryTableSize]; - Entry secondary_[kSecondaryTableSize]; + Handle ComputeCallInitialize(int argc, + RelocInfo::Mode mode, + Code::Kind kind); // Computes the hashed offsets for primary and secondary caches. static int PrimaryOffset(String* name, Code::Flags flags, Map* map) { @@ -367,8 +347,16 @@ class StubCache { reinterpret_cast
(table) + (offset << shift_amount)); } + static const int kPrimaryTableSize = 2048; + static const int kSecondaryTableSize = 512; + + Entry primary_[kPrimaryTableSize]; + Entry secondary_[kSecondaryTableSize]; Isolate* isolate_; + friend class Isolate; + friend class SCTableReference; + DISALLOW_COPY_AND_ASSIGN(StubCache); }; @@ -396,15 +384,31 @@ class StubCompiler BASE_EMBEDDED { explicit StubCompiler(Isolate* isolate) : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { } - MUST_USE_RESULT MaybeObject* CompileCallInitialize(Code::Flags flags); - MUST_USE_RESULT MaybeObject* CompileCallPreMonomorphic(Code::Flags flags); - MUST_USE_RESULT MaybeObject* CompileCallNormal(Code::Flags flags); - MUST_USE_RESULT MaybeObject* CompileCallMegamorphic(Code::Flags flags); - MUST_USE_RESULT MaybeObject* CompileCallArguments(Code::Flags flags); - MUST_USE_RESULT MaybeObject* CompileCallMiss(Code::Flags flags); + Handle CompileCallInitialize(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallInitialize(Code::Flags flags); + + Handle CompileCallPreMonomorphic(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallPreMonomorphic(Code::Flags flags); + + Handle CompileCallNormal(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallNormal(Code::Flags flags); + + Handle CompileCallMegamorphic(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallMegamorphic(Code::Flags flags); + + Handle CompileCallArguments(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallArguments(Code::Flags flags); + + Handle CompileCallMiss(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallMiss(Code::Flags flags); + #ifdef ENABLE_DEBUGGER_SUPPORT - MUST_USE_RESULT MaybeObject* CompileCallDebugBreak(Code::Flags flags); - MUST_USE_RESULT MaybeObject* CompileCallDebugPrepareStepIn(Code::Flags flags); + Handle CompileCallDebugBreak(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallDebugBreak(Code::Flags flags); + + Handle CompileCallDebugPrepareStepIn(Code::Flags flags); + MUST_USE_RESULT MaybeObject* TryCompileCallDebugPrepareStepIn( + Code::Flags flags); #endif // Static functions for generating parts of stubs. @@ -811,33 +815,50 @@ class CallStubCompiler: public StubCompiler { CallStubCompiler(Isolate* isolate, int argc, Code::Kind kind, - Code::ExtraICState extra_ic_state, + Code::ExtraICState extra_state, InlineCacheHolderFlag cache_holder); - MUST_USE_RESULT MaybeObject* CompileCallField( - JSObject* object, - JSObject* holder, - int index, - String* name); + Handle CompileCallField(Handle object, + Handle holder, + int index, + Handle name); - MUST_USE_RESULT MaybeObject* CompileCallConstant( - Object* object, - JSObject* holder, - JSFunction* function, - String* name, - CheckType check); + MUST_USE_RESULT MaybeObject* CompileCallField(JSObject* object, + JSObject* holder, + int index, + String* name); - MUST_USE_RESULT MaybeObject* CompileCallInterceptor( - JSObject* object, - JSObject* holder, - String* name); + Handle CompileCallConstant(Handle object, + Handle holder, + Handle function, + Handle name, + CheckType check); - MUST_USE_RESULT MaybeObject* CompileCallGlobal( - JSObject* object, - GlobalObject* holder, - JSGlobalPropertyCell* cell, - JSFunction* function, - String* name); + MUST_USE_RESULT MaybeObject* CompileCallConstant(Object* object, + JSObject* holder, + JSFunction* function, + String* name, + CheckType check); + + Handle CompileCallInterceptor(Handle object, + Handle holder, + Handle name); + + MUST_USE_RESULT MaybeObject* CompileCallInterceptor(JSObject* object, + JSObject* holder, + String* name); + + Handle CompileCallGlobal(Handle object, + Handle holder, + Handle cell, + Handle function, + Handle name); + + MUST_USE_RESULT MaybeObject* CompileCallGlobal(JSObject* object, + GlobalObject* holder, + JSGlobalPropertyCell* cell, + JSFunction* function, + String* name); static bool HasCustomCallGenerator(JSFunction* function); @@ -870,7 +891,7 @@ class CallStubCompiler: public StubCompiler { const ParameterCount arguments_; const Code::Kind kind_; - const Code::ExtraICState extra_ic_state_; + const Code::ExtraICState extra_state_; const InlineCacheHolderFlag cache_holder_; const ParameterCount& arguments() { return arguments_; } diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 6fae19430b..e3d463400f 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -3120,29 +3120,16 @@ void MacroAssembler::InvokeFunction(JSFunction* function, // You can't call a function without a valid frame. ASSERT(flag == JUMP_FUNCTION || has_frame()); - ASSERT(function->is_compiled()); // Get the function and setup the context. Move(rdi, Handle(function)); movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); - if (V8::UseCrankshaft()) { - // Since Crankshaft can recompile a function, we need to load - // the Code object every time we call the function. - movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); - ParameterCount expected(function->shared()->formal_parameter_count()); - InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind); - } else { - // Invoke the cached code. - Handle code(function->code()); - ParameterCount expected(function->shared()->formal_parameter_count()); - InvokeCode(code, - expected, - actual, - RelocInfo::CODE_TARGET, - flag, - call_wrapper, - call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + ParameterCount expected(function->shared()->formal_parameter_count()); + InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind); } diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 39e6fb733d..bd723df653 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -1307,9 +1307,9 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, MaybeObject* CallStubCompiler::GenerateMissBranch() { MaybeObject* maybe_obj = - isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), - kind_, - extra_ic_state_); + isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(), + kind_, + extra_state_); Object* obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ Jump(Handle(Code::cast(obj)), RelocInfo::CODE_TARGET); @@ -1360,7 +1360,7 @@ MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, } // Invoke the function. - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, @@ -1669,7 +1669,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } @@ -1753,7 +1753,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( Label* index_out_of_range_label = &index_out_of_range; if (kind_ == Code::CALL_IC && - (CallICBase::StringStubState::decode(extra_ic_state_) == + (CallICBase::StringStubState::decode(extra_state_) == DEFAULT_STRING_STUB)) { index_out_of_range_label = &miss; } @@ -1871,7 +1871,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall( // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -1988,7 +1988,7 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object, // Tail call the full function. We do not have to patch the receiver // because the function makes no use of it. __ bind(&slow); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -2186,7 +2186,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, UNREACHABLE(); } - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(function, arguments(), JUMP_FUNCTION, @@ -2227,7 +2227,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Get the receiver from the stack. __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); - CallInterceptorCompiler compiler(this, arguments(), rcx, extra_ic_state_); + CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_); MaybeObject* result = compiler.Compile(masm(), object, holder, @@ -2257,7 +2257,7 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, // Invoke the function. __ movq(rdi, rax); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, @@ -2320,24 +2320,17 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, // Jump to the cached code (tail call). Counters* counters = isolate()->counters(); __ IncrementCounter(counters->call_global_inline(), 1); - ASSERT(function->is_compiled()); ParameterCount expected(function->shared()->formal_parameter_count()); - CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) + CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION : CALL_AS_METHOD; - if (V8::UseCrankshaft()) { - // TODO(kasperl): For now, we always call indirectly through the - // code field in the function to allow recompilation to take effect - // without changing any of the call sites. - __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); - __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } else { - Handle code(function->code()); - __ InvokeCode(code, expected, arguments(), - RelocInfo::CODE_TARGET, JUMP_FUNCTION, - NullCallWrapper(), call_kind); - } + // We call indirectly through the code field in the function to + // allow recompilation to take effect without changing any of the + // call sites. + __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION, + NullCallWrapper(), call_kind); + // Handle call cache miss. __ bind(&miss); __ IncrementCounter(counters->call_global_inline_miss(), 1); diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index de60d4999d..cf723bafbd 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -409,11 +409,8 @@ Handle GetDebuggedFunctions() { static Handle ComputeCallDebugBreak(int argc) { - CALL_HEAP_FUNCTION( - v8::internal::Isolate::Current(), - v8::internal::Isolate::Current()->stub_cache()->ComputeCallDebugBreak( - argc, Code::CALL_IC), - Code); + return Isolate::Current()->stub_cache()->ComputeCallDebugBreak(argc, + Code::CALL_IC); } @@ -425,8 +422,8 @@ void CheckDebuggerUnloaded(bool check_functions) { CHECK_EQ(NULL, Isolate::Current()->debug()->debug_info_list_); // Collect garbage to ensure weak handles are cleared. - HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask); // Iterate the head and check that there are no debugger related objects left. HeapIterator iterator;