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
This commit is contained in:
kmillikin@chromium.org 2011-10-20 17:08:53 +00:00
parent a5da9320d2
commit e3792a6830
14 changed files with 663 additions and 791 deletions

View File

@ -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<JSFunction>(function)));
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Invoke the cached code.
Handle<Code> 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);
}

View File

@ -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>(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> 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);

View File

@ -87,19 +87,13 @@ static void PrintLn(v8::Local<v8::Value> value) {
static Handle<Code> 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<Code> 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);
}

View File

@ -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<JSFunction>(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> 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);
}

View File

@ -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>(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> 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);

217
src/ic.cc
View File

@ -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> object,
Handle<String> name) {
Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
State state,
Code::ExtraICState extra_state,
Handle<Object> object,
Handle<String> name) {
int argc = target()->arguments_count();
MaybeObject* maybe_code = NULL;
Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
kind_,
extra_ic_state,
*name,
*object,
lookup->holder(),
index);
break;
return isolate()->stub_cache()->ComputeCallField(
argc, kind_, extra_state, name, object, holder, index);
}
case CONSTANT_FUNCTION: {
// Get the constant function and compute the code stub for this
// call; used for rewriting to monomorphic state and making sure
// that the code stub is in the stub cache.
JSFunction* function = lookup->GetConstantFunction();
maybe_code =
isolate()->stub_cache()->ComputeCallConstant(argc,
kind_,
extra_ic_state,
*name,
*object,
lookup->holder(),
function);
break;
Handle<JSFunction> function(lookup->GetConstantFunction());
return isolate()->stub_cache()->ComputeCallConstant(
argc, kind_, extra_state, name, object, holder, function);
}
case NORMAL: {
if (!object->IsJSObject()) return NULL;
// If we return a null handle, the IC will not be patched.
if (!object->IsJSObject()) return Handle<Code>::null();
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
if (lookup->holder()->IsGlobalObject()) {
GlobalObject* global = GlobalObject::cast(lookup->holder());
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
if (!cell->value()->IsJSFunction()) return NULL;
JSFunction* function = JSFunction::cast(cell->value());
maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
kind_,
extra_ic_state,
*name,
*receiver,
global,
cell,
function);
if (holder->IsGlobalObject()) {
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
Handle<JSFunction> function(JSFunction::cast(cell->value()));
return isolate()->stub_cache()->ComputeCallGlobal(
argc, kind_, extra_state, name, receiver, global, cell, function);
} else {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
if (lookup->holder() != *receiver) return NULL;
maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
kind_,
extra_ic_state,
*name,
*receiver);
if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
return isolate()->stub_cache()->ComputeCallNormal(
argc, kind_, extra_state);
}
break;
}
case INTERCEPTOR: {
ASSERT(HasInterceptorGetter(lookup->holder()));
maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
argc,
kind_,
extra_ic_state,
*name,
*object,
lookup->holder());
break;
}
case INTERCEPTOR:
ASSERT(HasInterceptorGetter(*holder));
return isolate()->stub_cache()->ComputeCallInterceptor(
argc, kind_, extra_state, name, object, holder);
default:
maybe_code = NULL;
break;
return Handle<Code>::null();
}
return maybe_code;
}
@ -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> code;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
maybe_code =
isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
kind_,
extra_ic_state);
code = isolate()->stub_cache()->ComputeCallPreMonomorphic(
argc, kind_, extra_ic_state);
} else if (state == MONOMORPHIC) {
if (kind_ == Code::CALL_IC &&
TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
maybe_code = ComputeMonomorphicStub(lookup,
state,
extra_ic_state,
object,
name);
code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
object, name);
} else if (kind_ == Code::CALL_IC &&
TryRemoveInvalidPrototypeDependentStub(target(),
*object,
*name)) {
had_proto_failure = true;
maybe_code = ComputeMonomorphicStub(lookup,
state,
extra_ic_state,
object,
name);
code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
object, name);
} else {
maybe_code =
isolate()->stub_cache()->ComputeCallMegamorphic(argc,
kind_,
extra_ic_state);
code = isolate()->stub_cache()->ComputeCallMegamorphic(
argc, kind_, extra_ic_state);
}
} else {
maybe_code = ComputeMonomorphicStub(lookup,
state,
extra_ic_state,
object,
name);
code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
object, name);
}
// If we're unable to compute the stub (not enough memory left), we
// simply avoid updating the caches.
Object* code;
if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
// If there's no appropriate stub we simply avoid updating the caches.
if (code.is_null()) return;
// Patch the call site depending on the state of the cache.
if (state == UNINITIALIZED ||
state == PREMONOMORPHIC ||
state == MONOMORPHIC ||
state == MONOMORPHIC_PROTOTYPE_FAILURE) {
set_target(Code::cast(code));
set_target(*code);
} else if (state == MEGAMORPHIC) {
// Cache code holding map should be consistent with
// GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
Map* map = JSObject::cast(object->IsJSObject() ? *object :
object->GetPrototype())->map();
Handle<JSObject> cache_object = object->IsJSObject()
? Handle<JSObject>::cast(object)
: Handle<JSObject>(JSObject::cast(object->GetPrototype()));
// Update the stub cache.
isolate()->stub_cache()->Set(*name, map, Code::cast(code));
isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
}
USE(had_proto_failure);
#ifdef DEBUG
if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
name, state, target());
#endif
TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
name, state, target());
}
@ -774,25 +728,15 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
isolate()->factory()->non_strict_arguments_elements_map();
if (object->IsJSObject() &&
Handle<JSObject>::cast(object)->elements()->map() == *map) {
MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
Handle<Code> 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> 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.
//

View File

@ -216,12 +216,12 @@ class CallICBase: public IC {
Handle<Object> object,
Code::ExtraICState* extra_ic_state);
MUST_USE_RESULT MaybeObject* ComputeMonomorphicStub(
LookupResult* lookup,
State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name);
// Compute a monomorphic stub if possible, otherwise return a null handle.
Handle<Code> ComputeMonomorphicStub(LookupResult* lookup,
State state,
Code::ExtraICState extra_state,
Handle<Object> object,
Handle<String> name);
// Update the inline cache and the global stub cache based on the lookup
// result.

View File

@ -3246,10 +3246,10 @@ void NormalizedMapCache::Clear() {
}
void JSObject::UpdateMapCodeCache(Isolate* isolate,
Handle<JSObject> object,
void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
Handle<String> name,
Handle<Code> code) {
Isolate* isolate = object->GetIsolate();
CALL_HEAP_FUNCTION_VOID(isolate,
object->UpdateMapCodeCache(*name, *code));
}

View File

@ -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<JSObject> object,
static void UpdateMapCodeCache(Handle<JSObject> object,
Handle<String> name,
Handle<Code> code);

File diff suppressed because it is too large Load Diff

View File

@ -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<Code> ComputeCallField(int argc,
Code::Kind,
Code::ExtraICState extra_state,
Handle<String> name,
Handle<Object> object,
Handle<JSObject> 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<Code> ComputeCallConstant(int argc,
Code::Kind,
Code::ExtraICState extra_state,
Handle<String> name,
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSFunction> function);
MUST_USE_RESULT MaybeObject* ComputeCallNormal(
int argc,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
JSObject* receiver);
Handle<Code> ComputeCallInterceptor(int argc,
Code::Kind,
Code::ExtraICState extra_state,
Handle<String> name,
Handle<Object> object,
Handle<JSObject> 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<Code> ComputeCallGlobal(int argc,
Code::Kind,
Code::ExtraICState extra_state,
Handle<String> name,
Handle<JSObject> receiver,
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function);
// ---
MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc,
RelocInfo::Mode mode,
Code::Kind kind);
Handle<Code> ComputeCallInitialize(int argc,
RelocInfo::Mode mode);
Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
Handle<Code> ComputeKeyedCallInitialize(int argc);
MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic(
int argc,
Code::Kind kind,
Code::ExtraICState extra_ic_state);
Handle<Code> ComputeCallPreMonomorphic(int argc,
Code::Kind kind,
Code::ExtraICState extra_state);
MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc,
Code::Kind kind,
Code::ExtraICState state);
Handle<Code> ComputeCallNormal(int argc,
Code::Kind kind,
Code::ExtraICState state);
MUST_USE_RESULT MaybeObject* ComputeCallArguments(int argc,
Code::Kind kind);
Handle<Code> ComputeCallArguments(int argc, Code::Kind kind);
MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc,
Code::Kind kind,
Code::ExtraICState state);
Handle<Code> ComputeCallMegamorphic(int argc,
Code::Kind kind,
Code::ExtraICState state);
MUST_USE_RESULT MaybeObject* ComputeCallMiss(int argc,
Code::Kind kind,
Code::ExtraICState state);
Handle<Code> 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<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
MUST_USE_RESULT MaybeObject* ComputeCallDebugPrepareStepIn(int argc,
Code::Kind kind);
Handle<Code> 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<Code> 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<Address>(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<Code> CompileCallInitialize(Code::Flags flags);
MUST_USE_RESULT MaybeObject* TryCompileCallInitialize(Code::Flags flags);
Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
MUST_USE_RESULT MaybeObject* TryCompileCallPreMonomorphic(Code::Flags flags);
Handle<Code> CompileCallNormal(Code::Flags flags);
MUST_USE_RESULT MaybeObject* TryCompileCallNormal(Code::Flags flags);
Handle<Code> CompileCallMegamorphic(Code::Flags flags);
MUST_USE_RESULT MaybeObject* TryCompileCallMegamorphic(Code::Flags flags);
Handle<Code> CompileCallArguments(Code::Flags flags);
MUST_USE_RESULT MaybeObject* TryCompileCallArguments(Code::Flags flags);
Handle<Code> 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<Code> CompileCallDebugBreak(Code::Flags flags);
MUST_USE_RESULT MaybeObject* TryCompileCallDebugBreak(Code::Flags flags);
Handle<Code> 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<Code> CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
int index,
Handle<String> 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<Code> CompileCallConstant(Handle<Object> object,
Handle<JSObject> holder,
Handle<JSFunction> function,
Handle<String> 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<Code> CompileCallInterceptor(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name);
MUST_USE_RESULT MaybeObject* CompileCallInterceptor(JSObject* object,
JSObject* holder,
String* name);
Handle<Code> CompileCallGlobal(Handle<JSObject> object,
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> 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_; }

View File

@ -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<JSFunction>(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> 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);
}

View File

@ -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>(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> 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);

View File

@ -409,11 +409,8 @@ Handle<FixedArray> GetDebuggedFunctions() {
static Handle<Code> 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;