Introduce extra IC state to record additional feedback from IC-s.

Extra IC state is only two bits and only supported for call IC-s for
now. To change its extra state an IC stub jumps to a new miss stub
that goes to runtime as usual but then instead of going megamorphic
generates a monomorphic stub with the updated state.

Review URL: http://codereview.chromium.org/6344005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6370 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vitalyr@chromium.org 2011-01-18 16:54:48 +00:00
parent b4c88d5de4
commit 11a4cb5718
14 changed files with 505 additions and 213 deletions

View File

@ -542,8 +542,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Label number, non_number, non_string, boolean, probe, miss;
// Probe the stub cache.
Code::Flags flags =
Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
MONOMORPHIC,
Code::kNoExtraICState,
NORMAL,
argc);
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
// If the stub cache probing failed, the receiver might be a value.

View File

@ -1332,11 +1332,10 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
kind_);
Object* obj;
{ MaybeObject* maybe_obj =
StubCache::ComputeCallMiss(arguments().immediate(), kind_);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
return obj;
}
@ -1646,8 +1645,15 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
GenerateNameCheck(name, &miss);
Label* index_out_of_range_label = &index_out_of_range;
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@ -1675,7 +1681,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
result,
&miss, // When not a string.
&miss, // When not a number.
&index_out_of_range,
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_code_at_generator.GenerateFast(masm());
__ Drop(argc + 1);
@ -1684,12 +1690,17 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
StubRuntimeCallHelper call_helper;
char_code_at_generator.GenerateSlow(masm(), call_helper);
__ bind(&index_out_of_range);
__ LoadRoot(r0, Heap::kNanValueRootIndex);
__ Drop(argc + 1);
__ Ret();
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
__ LoadRoot(r0, Heap::kNanValueRootIndex);
__ Drop(argc + 1);
__ Ret();
}
__ bind(&miss);
// Restore function name in r2.
__ Move(r2, Handle<String>(name));
__ bind(&name_miss);
Object* obj;
{ MaybeObject* maybe_obj = GenerateMissBranch();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@ -1720,9 +1731,15 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
GenerateNameCheck(name, &miss);
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@ -1752,7 +1769,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
result,
&miss, // When not a string.
&miss, // When not a number.
&index_out_of_range,
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_at_generator.GenerateFast(masm());
__ Drop(argc + 1);
@ -1761,12 +1778,17 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
StubRuntimeCallHelper call_helper;
char_at_generator.GenerateSlow(masm(), call_helper);
__ bind(&index_out_of_range);
__ LoadRoot(r0, Heap::kEmptyStringRootIndex);
__ Drop(argc + 1);
__ Ret();
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
__ LoadRoot(r0, Heap::kEmptyStringRootIndex);
__ Drop(argc + 1);
__ Ret();
}
__ bind(&miss);
// Restore function name in r2.
__ Move(r2, Handle<String>(name));
__ bind(&name_miss);
Object* obj;
{ MaybeObject* maybe_obj = GenerateMissBranch();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;

View File

@ -1231,8 +1231,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Label number, non_number, non_string, boolean, probe, miss;
// Probe the stub cache.
Code::Flags flags =
Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
MONOMORPHIC,
Code::kNoExtraICState,
NORMAL,
argc);
StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
// If the stub cache probing failed, the receiver might be a value.
@ -1325,7 +1329,9 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) {
}
static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
static void GenerateCallMiss(MacroAssembler* masm,
int argc,
IC::UtilityId id) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address

View File

@ -1362,11 +1362,10 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
kind_);
Object* obj;
{ MaybeObject* maybe_obj =
StubCache::ComputeCallMiss(arguments().immediate(), kind_);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
return obj;
}
@ -1685,9 +1684,15 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
GenerateNameCheck(name, &miss);
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@ -1715,7 +1720,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
result,
&miss, // When not a string.
&miss, // When not a number.
&index_out_of_range,
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_code_at_generator.GenerateFast(masm());
__ ret((argc + 1) * kPointerSize);
@ -1723,11 +1728,16 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
StubRuntimeCallHelper call_helper;
char_code_at_generator.GenerateSlow(masm(), call_helper);
__ bind(&index_out_of_range);
__ Set(eax, Immediate(Factory::nan_value()));
__ ret((argc + 1) * kPointerSize);
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
__ Set(eax, Immediate(Factory::nan_value()));
__ ret((argc + 1) * kPointerSize);
}
__ bind(&miss);
// Restore function name in ecx.
__ Set(ecx, Immediate(Handle<String>(name)));
__ bind(&name_miss);
Object* obj;
{ MaybeObject* maybe_obj = GenerateMissBranch();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@ -1758,9 +1768,15 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
GenerateNameCheck(name, &miss);
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@ -1790,7 +1806,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
result,
&miss, // When not a string.
&miss, // When not a number.
&index_out_of_range,
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_at_generator.GenerateFast(masm());
__ ret((argc + 1) * kPointerSize);
@ -1798,11 +1814,16 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
StubRuntimeCallHelper call_helper;
char_at_generator.GenerateSlow(masm(), call_helper);
__ bind(&index_out_of_range);
__ Set(eax, Immediate(Factory::empty_string()));
__ ret((argc + 1) * kPointerSize);
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
__ Set(eax, Immediate(Factory::empty_string()));
__ ret((argc + 1) * kPointerSize);
}
__ bind(&miss);
// Restore function name in ecx.
__ Set(ecx, Immediate(Handle<String>(name)));
__ bind(&name_miss);
Object* obj;
{ MaybeObject* maybe_obj = GenerateMissBranch();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;

309
src/ic.cc
View File

@ -154,24 +154,20 @@ static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup,
}
IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
IC::State state = target->ic_state();
if (state != MONOMORPHIC || !name->IsString()) return state;
if (receiver->IsUndefined() || receiver->IsNull()) return state;
static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
Object* receiver,
Object* name) {
InlineCacheHolderFlag cache_holder =
Code::ExtractCacheHolderFromFlags(target->flags());
if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
// The stub was generated for JSObject but called for non-JSObject.
// IC::GetCodeCacheHolder is not applicable.
return MONOMORPHIC;
return false;
} else if (cache_holder == PROTOTYPE_MAP &&
receiver->GetPrototype()->IsNull()) {
// IC::GetCodeCacheHolder is not applicable.
return MONOMORPHIC;
return false;
}
Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
@ -185,20 +181,37 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
// to prototype check failure.
int index = map->IndexInCodeCache(name, target);
if (index >= 0) {
// For keyed load/store/call, the most likely cause of cache failure is
// that the key has changed. We do not distinguish between
// prototype and non-prototype failures for keyed access.
Code::Kind kind = target->kind();
if (kind == Code::KEYED_LOAD_IC ||
kind == Code::KEYED_STORE_IC ||
kind == Code::KEYED_CALL_IC) {
return MONOMORPHIC;
}
// Remove the target from the code cache to avoid hitting the same
// invalid stub again.
map->RemoveFromCodeCache(String::cast(name), target, index);
return true;
}
return false;
}
IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
IC::State state = target->ic_state();
if (state != MONOMORPHIC || !name->IsString()) return state;
if (receiver->IsUndefined() || receiver->IsNull()) return state;
// For keyed load/store/call, the most likely cause of cache failure is
// that the key has changed. We do not distinguish between
// prototype and non-prototype failures for keyed access.
Code::Kind kind = target->kind();
if (kind == Code::KEYED_LOAD_IC ||
kind == Code::KEYED_STORE_IC ||
kind == Code::KEYED_CALL_IC) {
return MONOMORPHIC;
}
// Remove the target from the code cache if it became invalid
// because of changes in the prototype chain to avoid hitting it
// again.
// Call stubs handle this later to allow extra IC state
// transitions.
if (kind != Code::CALL_IC &&
TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
return MONOMORPHIC_PROTOTYPE_FAILURE;
}
@ -482,6 +495,7 @@ void CallICBase::ReceiverToObject(Handle<Object> object) {
MaybeObject* CallICBase::LoadFunction(State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name) {
// If the object is undefined or null it's illegal to try to get any
@ -527,7 +541,7 @@ MaybeObject* CallICBase::LoadFunction(State state,
// Lookup is valid: Update inline cache and stub cache.
if (FLAG_use_ic) {
UpdateCaches(&lookup, state, object, name);
UpdateCaches(&lookup, state, extra_ic_state, object, name);
}
// Get the property.
@ -576,8 +590,142 @@ MaybeObject* CallICBase::LoadFunction(State state,
}
bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
Handle<Object> object,
Code::ExtraICState* extra_ic_state) {
ASSERT(kind_ == Code::CALL_IC);
if (lookup->type() != CONSTANT_FUNCTION) return false;
JSFunction* function = lookup->GetConstantFunction();
if (!function->shared()->HasBuiltinFunctionId()) return false;
// Fetch the arguments passed to the called function.
const int argc = target()->arguments_count();
Address entry = Top::c_entry_fp(Top::GetCurrentThread());
Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
Arguments args(argc + 1,
&Memory::Object_at(fp +
StandardFrameConstants::kCallerSPOffset +
argc * kPointerSize));
switch (function->shared()->builtin_function_id()) {
case kStringCharCodeAt:
case kStringCharAt:
if (object->IsString()) {
String* string = String::cast(*object);
// Check that there's the right wrapper in the receiver slot.
ASSERT(string == JSValue::cast(args[0])->value());
// If we're in the default (fastest) state and the index is
// out of bounds, update the state to record this fact.
if (*extra_ic_state == DEFAULT_STRING_STUB &&
argc >= 1 && args[1]->IsNumber()) {
double index;
if (args[1]->IsSmi()) {
index = Smi::cast(args[1])->value();
} else {
ASSERT(args[1]->IsHeapNumber());
index = DoubleToInteger(HeapNumber::cast(args[1])->value());
}
if (index < 0 || index >= string->length()) {
*extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS;
return true;
}
}
}
break;
default:
return false;
}
return false;
}
MaybeObject* CallICBase::ComputeMonomorphicStub(
LookupResult* lookup,
State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name) {
int argc = target()->arguments_count();
InLoopFlag in_loop = target()->ic_in_loop();
MaybeObject* maybe_code = NULL;
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
maybe_code = StubCache::ComputeCallField(argc,
in_loop,
kind_,
*name,
*object,
lookup->holder(),
index);
break;
}
case CONSTANT_FUNCTION: {
// Get the constant function and compute the code stub for this
// call; used for rewriting to monomorphic state and making sure
// that the code stub is in the stub cache.
JSFunction* function = lookup->GetConstantFunction();
maybe_code = StubCache::ComputeCallConstant(argc,
in_loop,
kind_,
extra_ic_state,
*name,
*object,
lookup->holder(),
function);
break;
}
case NORMAL: {
if (!object->IsJSObject()) return 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 = StubCache::ComputeCallGlobal(argc,
in_loop,
kind_,
*name,
*receiver,
global,
cell,
function);
} else {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
if (lookup->holder() != *receiver) return NULL;
maybe_code = StubCache::ComputeCallNormal(argc,
in_loop,
kind_,
*name,
*receiver);
}
break;
}
case INTERCEPTOR: {
ASSERT(HasInterceptorGetter(lookup->holder()));
maybe_code = StubCache::ComputeCallInterceptor(argc,
kind_,
*name,
*object,
lookup->holder());
break;
}
default:
maybe_code = NULL;
break;
}
return maybe_code;
}
void CallICBase::UpdateCaches(LookupResult* lookup,
State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name) {
// Bail out if we didn't find a result.
@ -594,90 +742,44 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
int argc = target()->arguments_count();
InLoopFlag in_loop = target()->ic_in_loop();
MaybeObject* maybe_code = NULL;
Object* code;
bool had_proto_failure = false;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_);
} else if (state == MONOMORPHIC) {
maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_);
} else {
// Compute monomorphic stub.
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
maybe_code = StubCache::ComputeCallField(argc,
in_loop,
kind_,
*name,
*object,
lookup->holder(),
index);
break;
}
case CONSTANT_FUNCTION: {
// Get the constant function and compute the code stub for this
// call; used for rewriting to monomorphic state and making sure
// that the code stub is in the stub cache.
JSFunction* function = lookup->GetConstantFunction();
maybe_code = StubCache::ComputeCallConstant(argc,
in_loop,
kind_,
*name,
*object,
lookup->holder(),
function);
break;
}
case NORMAL: {
if (!object->IsJSObject()) return;
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;
JSFunction* function = JSFunction::cast(cell->value());
maybe_code = StubCache::ComputeCallGlobal(argc,
in_loop,
kind_,
*name,
*receiver,
global,
cell,
function);
} else {
// There is only one shared stub for calling normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// applicable.
if (lookup->holder() != *receiver) return;
maybe_code = StubCache::ComputeCallNormal(argc,
in_loop,
kind_,
*name,
*receiver);
}
break;
}
case INTERCEPTOR: {
ASSERT(HasInterceptorGetter(lookup->holder()));
maybe_code = StubCache::ComputeCallInterceptor(argc,
kind_,
*name,
*object,
lookup->holder());
break;
}
default:
return;
if (kind_ == Code::CALL_IC &&
TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
maybe_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);
} else {
maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_);
}
} else {
maybe_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;
// Patch the call site depending on the state of the cache.
@ -696,7 +798,9 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
StubCache::Set(*name, map, Code::cast(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(), in_loop ? " (in-loop)" : "");
#endif
@ -707,7 +811,10 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
Handle<Object> object,
Handle<Object> key) {
if (key->IsSymbol()) {
return CallICBase::LoadFunction(state, object, Handle<String>::cast(key));
return CallICBase::LoadFunction(state,
Code::kNoExtraICState,
object,
Handle<String>::cast(key));
}
if (object->IsUndefined() || object->IsNull()) {
@ -1641,11 +1748,13 @@ MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) {
ASSERT(args.length() == 2);
CallIC ic;
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
MaybeObject* maybe_result = ic.LoadFunction(state,
extra_ic_state,
args.at<Object>(0),
args.at<String>(1));
Object* result;
{ MaybeObject* maybe_result =
ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
if (!maybe_result->ToObject(&result)) return maybe_result;
}
if (!maybe_result->ToObject(&result)) return maybe_result;
// The first time the inline cache is updated may be the first time the
// function it references gets called. If the function was lazily compiled

View File

@ -193,16 +193,29 @@ class CallICBase: public IC {
public:
MUST_USE_RESULT MaybeObject* LoadFunction(State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name);
protected:
Code::Kind kind_;
bool TryUpdateExtraICState(LookupResult* lookup,
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);
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupResult* lookup,
State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name);

View File

@ -2416,6 +2416,12 @@ InlineCacheState Code::ic_state() {
}
Code::ExtraICState Code::extra_ic_state() {
ASSERT(is_inline_cache_stub());
return ExtractExtraICStateFromFlags(flags());
}
PropertyType Code::type() {
ASSERT(ic_state() == MONOMORPHIC);
return ExtractTypeFromFlags(flags());
@ -2592,14 +2598,20 @@ bool Code::is_inline_cache_stub() {
Code::Flags Code::ComputeFlags(Kind kind,
InLoopFlag in_loop,
InlineCacheState ic_state,
ExtraICState extra_ic_state,
PropertyType type,
int argc,
InlineCacheHolderFlag holder) {
// Extra IC state is only allowed for monomorphic call IC stubs.
ASSERT(extra_ic_state == kNoExtraICState ||
(kind == CALL_IC && (ic_state == MONOMORPHIC ||
ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)));
// Compute the bit mask.
int bits = kind << kFlagsKindShift;
if (in_loop) bits |= kFlagsICInLoopMask;
bits |= ic_state << kFlagsICStateShift;
bits |= type << kFlagsTypeShift;
bits |= extra_ic_state << kFlagsExtraICStateShift;
bits |= argc << kFlagsArgumentsCountShift;
if (holder == PROTOTYPE_MAP) bits |= kFlagsCacheInPrototypeMapMask;
// Cast to flags and validate result before returning it.
@ -2608,6 +2620,7 @@ Code::Flags Code::ComputeFlags(Kind kind,
ASSERT(ExtractICStateFromFlags(result) == ic_state);
ASSERT(ExtractICInLoopFromFlags(result) == in_loop);
ASSERT(ExtractTypeFromFlags(result) == type);
ASSERT(ExtractExtraICStateFromFlags(result) == extra_ic_state);
ASSERT(ExtractArgumentsCountFromFlags(result) == argc);
return result;
}
@ -2615,10 +2628,12 @@ Code::Flags Code::ComputeFlags(Kind kind,
Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
PropertyType type,
ExtraICState extra_ic_state,
InlineCacheHolderFlag holder,
InLoopFlag in_loop,
int argc) {
return ComputeFlags(kind, in_loop, MONOMORPHIC, type, argc, holder);
return ComputeFlags(
kind, in_loop, MONOMORPHIC, extra_ic_state, type, argc, holder);
}
@ -2634,6 +2649,12 @@ InlineCacheState Code::ExtractICStateFromFlags(Flags flags) {
}
Code::ExtraICState Code::ExtractExtraICStateFromFlags(Flags flags) {
int bits = (flags & kFlagsExtraICStateMask) >> kFlagsExtraICStateShift;
return static_cast<ExtraICState>(bits);
}
InLoopFlag Code::ExtractICInLoopFromFlags(Flags flags) {
int bits = (flags & kFlagsICInLoopMask);
return bits != 0 ? IN_LOOP : NOT_IN_LOOP;

View File

@ -3168,6 +3168,10 @@ class Code: public HeapObject {
NUMBER_OF_KINDS = LAST_IC_KIND + 1
};
typedef int ExtraICState;
static const ExtraICState kNoExtraICState = 0;
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* Kind2String(Kind kind);
@ -3203,6 +3207,7 @@ class Code: public HeapObject {
// [flags]: Access to specific code flags.
inline Kind kind();
inline InlineCacheState ic_state(); // Only valid for IC stubs.
inline ExtraICState extra_ic_state(); // Only valid for IC stubs.
inline InLoopFlag ic_in_loop(); // Only valid for IC stubs.
inline PropertyType type(); // Only valid for monomorphic IC stubs.
inline int arguments_count(); // Only valid for call IC stubs.
@ -3287,22 +3292,26 @@ class Code: public HeapObject {
Map* FindFirstMap();
// Flags operations.
static inline Flags ComputeFlags(Kind kind,
InLoopFlag in_loop = NOT_IN_LOOP,
InlineCacheState ic_state = UNINITIALIZED,
PropertyType type = NORMAL,
int argc = -1,
InlineCacheHolderFlag holder = OWN_MAP);
static inline Flags ComputeFlags(
Kind kind,
InLoopFlag in_loop = NOT_IN_LOOP,
InlineCacheState ic_state = UNINITIALIZED,
ExtraICState extra_ic_state = kNoExtraICState,
PropertyType type = NORMAL,
int argc = -1,
InlineCacheHolderFlag holder = OWN_MAP);
static inline Flags ComputeMonomorphicFlags(
Kind kind,
PropertyType type,
ExtraICState extra_ic_state = kNoExtraICState,
InlineCacheHolderFlag holder = OWN_MAP,
InLoopFlag in_loop = NOT_IN_LOOP,
int argc = -1);
static inline Kind ExtractKindFromFlags(Flags flags);
static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
static inline InLoopFlag ExtractICInLoopFromFlags(Flags flags);
static inline PropertyType ExtractTypeFromFlags(Flags flags);
static inline int ExtractArgumentsCountFromFlags(Flags flags);
@ -3423,14 +3432,16 @@ class Code: public HeapObject {
static const int kFlagsTypeShift = 4;
static const int kFlagsKindShift = 7;
static const int kFlagsICHolderShift = 11;
static const int kFlagsArgumentsCountShift = 12;
static const int kFlagsExtraICStateShift = 12;
static const int kFlagsArgumentsCountShift = 14;
static const int kFlagsICStateMask = 0x00000007; // 00000000111
static const int kFlagsICInLoopMask = 0x00000008; // 00000001000
static const int kFlagsTypeMask = 0x00000070; // 00001110000
static const int kFlagsKindMask = 0x00000780; // 11110000000
static const int kFlagsCacheInPrototypeMapMask = 0x00000800;
static const int kFlagsArgumentsCountMask = 0xFFFFF000;
static const int kFlagsExtraICStateMask = 0x00003000;
static const int kFlagsArgumentsCountMask = 0xFFFFC000;
static const int kFlagsNotUsedInLookup =
(kFlagsICInLoopMask | kFlagsTypeMask | kFlagsCacheInPrototypeMapMask);

View File

@ -613,6 +613,7 @@ MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
MaybeObject* StubCache::ComputeCallConstant(int argc,
InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
Object* object,
JSObject* holder,
@ -632,12 +633,12 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
check = BOOLEAN_CHECK;
}
Code::Flags flags =
Code::ComputeMonomorphicFlags(kind,
CONSTANT_FUNCTION,
cache_holder,
in_loop,
argc);
Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
CONSTANT_FUNCTION,
extra_ic_state,
cache_holder,
in_loop,
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
@ -646,7 +647,8 @@ MaybeObject* StubCache::ComputeCallConstant(int argc,
// caches.
if (!function->is_compiled()) return Failure::InternalError();
// Compile the stub - only create stubs for fully compiled functions.
CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
CallStubCompiler compiler(
argc, in_loop, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallConstant(object, holder, function, name, check);
if (!maybe_code->ToObject(&code)) return maybe_code;
@ -687,12 +689,14 @@ MaybeObject* StubCache::ComputeCallField(int argc,
Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
FIELD,
Code::kNoExtraICState,
cache_holder,
in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
CallStubCompiler compiler(
argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallField(JSObject::cast(object),
holder,
@ -731,15 +735,16 @@ MaybeObject* StubCache::ComputeCallInterceptor(int argc,
object = holder;
}
Code::Flags flags =
Code::ComputeMonomorphicFlags(kind,
INTERCEPTOR,
cache_holder,
NOT_IN_LOOP,
argc);
Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
INTERCEPTOR,
Code::kNoExtraICState,
cache_holder,
NOT_IN_LOOP,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
CallStubCompiler compiler(argc, NOT_IN_LOOP, kind, cache_holder);
CallStubCompiler compiler(
argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
@ -782,12 +787,12 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(receiver, holder);
JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Code::Flags flags =
Code::ComputeMonomorphicFlags(kind,
NORMAL,
cache_holder,
in_loop,
argc);
Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
NORMAL,
Code::kNoExtraICState,
cache_holder,
in_loop,
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
@ -795,7 +800,8 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc,
// internal error which will make sure we do not update any
// caches.
if (!function->is_compiled()) return Failure::InternalError();
CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
CallStubCompiler compiler(
argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallGlobal(receiver, holder, cell, function, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
@ -862,8 +868,12 @@ static MaybeObject* FillCache(MaybeObject* maybe_code) {
Code* StubCache::FindCallInitialize(int argc,
InLoopFlag in_loop,
Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
in_loop,
UNINITIALIZED,
Code::kNoExtraICState,
NORMAL,
argc);
Object* result = ProbeCache(flags)->ToObjectUnchecked();
ASSERT(!result->IsUndefined());
// This might be called during the marking phase of the collector
@ -875,8 +885,12 @@ Code* StubCache::FindCallInitialize(int argc,
MaybeObject* StubCache::ComputeCallInitialize(int argc,
InLoopFlag in_loop,
Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
in_loop,
UNINITIALIZED,
Code::kNoExtraICState,
NORMAL,
argc);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -918,8 +932,12 @@ Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
InLoopFlag in_loop,
Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind, in_loop, PREMONOMORPHIC, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
in_loop,
PREMONOMORPHIC,
Code::kNoExtraICState,
NORMAL,
argc);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -933,8 +951,12 @@ MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
MaybeObject* StubCache::ComputeCallNormal(int argc,
InLoopFlag in_loop,
Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind, in_loop, MONOMORPHIC, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
in_loop,
MONOMORPHIC,
Code::kNoExtraICState,
NORMAL,
argc);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -948,8 +970,12 @@ MaybeObject* StubCache::ComputeCallNormal(int argc,
MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
InLoopFlag in_loop,
Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind, in_loop, MEGAMORPHIC, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
in_loop,
MEGAMORPHIC,
Code::kNoExtraICState,
NORMAL,
argc);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -963,8 +989,13 @@ MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
// 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, NOT_IN_LOOP, MONOMORPHIC_PROTOTYPE_FAILURE, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
MONOMORPHIC_PROTOTYPE_FAILURE,
Code::kNoExtraICState,
NORMAL,
argc,
OWN_MAP);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -977,8 +1008,12 @@ MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
#ifdef ENABLE_DEBUGGER_SUPPORT
MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
DEBUG_BREAK,
Code::kNoExtraICState,
NORMAL,
argc);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -991,12 +1026,12 @@ MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
Code::Kind kind) {
Code::Flags flags =
Code::ComputeFlags(kind,
NOT_IN_LOOP,
DEBUG_PREPARE_STEP_IN,
NORMAL,
argc);
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
DEBUG_PREPARE_STEP_IN,
Code::kNoExtraICState,
NORMAL,
argc);
Object* probe;
{ MaybeObject* maybe_probe = ProbeCache(flags);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
@ -1533,11 +1568,13 @@ MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
CallStubCompiler::CallStubCompiler(int argc,
InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
InlineCacheHolderFlag cache_holder)
: arguments_(argc)
, in_loop_(in_loop)
, kind_(kind)
, cache_holder_(cache_holder) {
: arguments_(argc),
in_loop_(in_loop),
kind_(kind),
extra_ic_state_(extra_ic_state),
cache_holder_(cache_holder) {
}
@ -1574,6 +1611,7 @@ MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
int argc = arguments_.immediate();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
type,
extra_ic_state_,
cache_holder_,
in_loop_,
argc);

View File

@ -177,13 +177,15 @@ class StubCache : public AllStatic {
JSObject* holder,
int index);
MUST_USE_RESULT static MaybeObject* ComputeCallConstant(int argc,
InLoopFlag in_loop,
Code::Kind,
String* name,
Object* object,
JSObject* holder,
JSFunction* function);
MUST_USE_RESULT static MaybeObject* ComputeCallConstant(
int argc,
InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
Object* object,
JSObject* holder,
JSFunction* function);
MUST_USE_RESULT static MaybeObject* ComputeCallNormal(int argc,
InLoopFlag in_loop,
@ -660,6 +662,7 @@ class CallStubCompiler: public StubCompiler {
CallStubCompiler(int argc,
InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
InlineCacheHolderFlag cache_holder);
MUST_USE_RESULT MaybeObject* CompileCallField(JSObject* object,
@ -705,6 +708,7 @@ class CallStubCompiler: public StubCompiler {
const ParameterCount arguments_;
const InLoopFlag in_loop_;
const Code::Kind kind_;
const Code::ExtraICState extra_ic_state_;
const InlineCacheHolderFlag cache_holder_;
const ParameterCount& arguments() { return arguments_; }

View File

@ -58,6 +58,9 @@ TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) {
}
STATIC_ASSERT(DEFAULT_STRING_STUB == Code::kNoExtraICState);
TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
Handle<Context> global_context) {
global_context_ = global_context;
@ -117,8 +120,16 @@ ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr,
Handle<String> name) {
int arity = expr->arguments()->length();
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::CALL_IC, NORMAL, OWN_MAP, NOT_IN_LOOP, arity);
// Note: these flags won't let us get maps from stubs with
// non-default extra ic state in the megamorphic case. In the more
// important monomorphic case the map is obtained directly, so it's
// not a problem until we decide to emit more polymorphic code.
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
NORMAL,
Code::kNoExtraICState,
OWN_MAP,
NOT_IN_LOOP,
arity);
return CollectReceiverTypes(expr->position(), name, flags);
}

View File

@ -219,6 +219,12 @@ class TypeInfo {
};
enum StringStubFeedback {
DEFAULT_STRING_STUB = 0,
STRING_INDEX_OUT_OF_BOUNDS = 1
};
// Forward declarations.
class Assignment;
class BinaryOperation;

View File

@ -1178,8 +1178,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Label number, non_number, non_string, boolean, probe, miss;
// Probe the stub cache.
Code::Flags flags =
Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
MONOMORPHIC,
Code::kNoExtraICState,
NORMAL,
argc);
StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax);
// If the stub cache probing failed, the receiver might be a value.

View File

@ -1327,8 +1327,8 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
MaybeObject* maybe_obj =
StubCache::ComputeCallMiss(arguments().immediate(), kind_);
MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(),
kind_);
Object* obj;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
@ -1660,9 +1660,15 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
GenerateNameCheck(name, &miss);
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@ -1690,7 +1696,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
result,
&miss, // When not a string.
&miss, // When not a number.
&index_out_of_range,
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_code_at_generator.GenerateFast(masm());
__ ret((argc + 1) * kPointerSize);
@ -1698,11 +1704,16 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
StubRuntimeCallHelper call_helper;
char_code_at_generator.GenerateSlow(masm(), call_helper);
__ bind(&index_out_of_range);
__ LoadRoot(rax, Heap::kNanValueRootIndex);
__ ret((argc + 1) * kPointerSize);
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
__ LoadRoot(rax, Heap::kNanValueRootIndex);
__ ret((argc + 1) * kPointerSize);
}
__ bind(&miss);
// Restore function name in rcx.
__ Move(rcx, Handle<String>(name));
__ bind(&name_miss);
Object* obj;
{ MaybeObject* maybe_obj = GenerateMissBranch();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@ -1733,9 +1744,15 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
GenerateNameCheck(name, &miss);
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
@ -1765,7 +1782,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
result,
&miss, // When not a string.
&miss, // When not a number.
&index_out_of_range,
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_at_generator.GenerateFast(masm());
__ ret((argc + 1) * kPointerSize);
@ -1773,11 +1790,16 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
StubRuntimeCallHelper call_helper;
char_at_generator.GenerateSlow(masm(), call_helper);
__ bind(&index_out_of_range);
__ LoadRoot(rax, Heap::kEmptyStringRootIndex);
__ ret((argc + 1) * kPointerSize);
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
__ LoadRoot(rax, Heap::kEmptyStringRootIndex);
__ ret((argc + 1) * kPointerSize);
}
__ bind(&miss);
// Restore function name in rcx.
__ Move(rcx, Handle<String>(name));
__ bind(&name_miss);
Object* obj;
{ MaybeObject* maybe_obj = GenerateMissBranch();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;