[stubs] KeyedLoadIC_Megamorphic: support getters

This extends the KeyedLoadIC_Megamorphic stub to call getters it found
on the receiver without falling back to a runtime call.

Review-Url: https://codereview.chromium.org/2362453004
Cr-Commit-Position: refs/heads/master@{#39688}
This commit is contained in:
jkummerow 2016-09-23 11:48:04 -07:00 committed by Commit bot
parent 713e247e7d
commit c636334829
3 changed files with 81 additions and 63 deletions

View File

@ -49,29 +49,6 @@ namespace internal {
// Args: name
#define BUILTIN_LIST(CPP, API, TFJ, TFS, ASM, ASH, DBG) \
ASM(Abort) \
/* Handlers */ \
ASH(KeyedLoadIC_Megamorphic, KEYED_LOAD_IC, kNoExtraICState) \
TFS(KeyedLoadIC_Megamorphic_TF, KEYED_LOAD_IC, kNoExtraICState, \
LoadWithVector) \
ASM(KeyedLoadIC_Miss) \
ASH(KeyedLoadIC_Slow, HANDLER, Code::KEYED_LOAD_IC) \
ASH(KeyedStoreIC_Megamorphic, KEYED_STORE_IC, kNoExtraICState) \
ASH(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, \
StoreICState::kStrictModeState) \
ASM(KeyedStoreIC_Miss) \
ASH(KeyedStoreIC_Slow, HANDLER, Code::KEYED_STORE_IC) \
TFS(LoadGlobalIC_Miss, BUILTIN, kNoExtraICState, LoadGlobalWithVector) \
TFS(LoadGlobalIC_Slow, HANDLER, Code::LOAD_GLOBAL_IC, LoadGlobalWithVector) \
ASH(LoadIC_Getter_ForDeopt, LOAD_IC, kNoExtraICState) \
TFS(LoadIC_Miss, BUILTIN, kNoExtraICState, LoadWithVector) \
ASH(LoadIC_Normal, HANDLER, Code::LOAD_IC) \
TFS(LoadIC_Slow, HANDLER, Code::LOAD_IC, LoadWithVector) \
TFS(StoreIC_Miss, BUILTIN, kNoExtraICState, StoreWithVector) \
ASH(StoreIC_Normal, HANDLER, Code::STORE_IC) \
ASH(StoreIC_Setter_ForDeopt, STORE_IC, StoreICState::kStrictModeState) \
TFS(StoreIC_SlowSloppy, HANDLER, Code::STORE_IC, StoreWithVector) \
TFS(StoreIC_SlowStrict, HANDLER, Code::STORE_IC, StoreWithVector) \
\
/* Code aging */ \
CODE_AGE_LIST_WITH_ARG(DECLARE_CODE_AGE_BUILTIN, ASM) \
\
@ -187,6 +164,29 @@ namespace internal {
TFS(NonNumberToNumber, BUILTIN, kNoExtraICState, TypeConversion) \
TFS(ToNumber, BUILTIN, kNoExtraICState, TypeConversion) \
\
/* Handlers */ \
ASH(KeyedLoadIC_Megamorphic, KEYED_LOAD_IC, kNoExtraICState) \
TFS(KeyedLoadIC_Megamorphic_TF, KEYED_LOAD_IC, kNoExtraICState, \
LoadWithVector) \
ASM(KeyedLoadIC_Miss) \
ASH(KeyedLoadIC_Slow, HANDLER, Code::KEYED_LOAD_IC) \
ASH(KeyedStoreIC_Megamorphic, KEYED_STORE_IC, kNoExtraICState) \
ASH(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, \
StoreICState::kStrictModeState) \
ASM(KeyedStoreIC_Miss) \
ASH(KeyedStoreIC_Slow, HANDLER, Code::KEYED_STORE_IC) \
TFS(LoadGlobalIC_Miss, BUILTIN, kNoExtraICState, LoadGlobalWithVector) \
TFS(LoadGlobalIC_Slow, HANDLER, Code::LOAD_GLOBAL_IC, LoadGlobalWithVector) \
ASH(LoadIC_Getter_ForDeopt, LOAD_IC, kNoExtraICState) \
TFS(LoadIC_Miss, BUILTIN, kNoExtraICState, LoadWithVector) \
ASH(LoadIC_Normal, HANDLER, Code::LOAD_IC) \
TFS(LoadIC_Slow, HANDLER, Code::LOAD_IC, LoadWithVector) \
TFS(StoreIC_Miss, BUILTIN, kNoExtraICState, StoreWithVector) \
ASH(StoreIC_Normal, HANDLER, Code::STORE_IC) \
ASH(StoreIC_Setter_ForDeopt, STORE_IC, StoreICState::kStrictModeState) \
TFS(StoreIC_SlowSloppy, HANDLER, Code::STORE_IC, StoreWithVector) \
TFS(StoreIC_SlowStrict, HANDLER, Code::STORE_IC, StoreWithVector) \
\
/* Built-in functions for Javascript */ \
/* Special internal builtins */ \
CPP(EmptyFunction) \

View File

@ -3565,6 +3565,52 @@ void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
Comment("] LoadPropertyFromGlobalDictionary");
}
// |value| is the property backing store's contents, which is either a value
// or an accessor pair, as specified by |details|.
// Returns either the original value, or the result of the getter call.
Node* CodeStubAssembler::CallGetterIfAccessor(Node* value, Node* details,
Node* context, Node* receiver,
Label* if_bailout) {
Variable var_value(this, MachineRepresentation::kTagged);
var_value.Bind(value);
Label done(this);
Node* kind = BitFieldDecode<PropertyDetails::KindField>(details);
GotoIf(Word32Equal(kind, Int32Constant(kData)), &done);
// Accessor case.
{
Node* accessor_pair = value;
GotoIf(Word32Equal(LoadInstanceType(accessor_pair),
Int32Constant(ACCESSOR_INFO_TYPE)),
if_bailout);
AssertInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE);
Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
Node* getter_map = LoadMap(getter);
Node* instance_type = LoadMapInstanceType(getter_map);
// FunctionTemplateInfo getters are not supported yet.
GotoIf(
Word32Equal(instance_type, Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
if_bailout);
// Return undefined if the {getter} is not callable.
var_value.Bind(UndefinedConstant());
GotoIf(Word32Equal(Word32And(LoadMapBitField(getter_map),
Int32Constant(1 << Map::kIsCallable)),
Int32Constant(0)),
&done);
// Call the accessor.
Callable callable = CodeFactory::Call(isolate());
Node* result = CallJS(callable, context, getter, receiver);
var_value.Bind(result);
Goto(&done);
}
Bind(&done);
return var_value.value();
}
void CodeStubAssembler::TryGetOwnProperty(
Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
Node* unique_name, Label* if_found_value, Variable* var_value,
@ -3612,41 +3658,10 @@ void CodeStubAssembler::TryGetOwnProperty(
// Here we have details and value which could be an accessor.
Bind(&if_found);
{
Node* details = var_details.value();
Node* kind = BitFieldDecode<PropertyDetails::KindField>(details);
Label if_accessor(this);
Branch(Word32Equal(kind, Int32Constant(kData)), if_found_value,
&if_accessor);
Bind(&if_accessor);
{
Node* accessor_pair = var_value->value();
GotoIf(Word32Equal(LoadInstanceType(accessor_pair),
Int32Constant(ACCESSOR_INFO_TYPE)),
if_bailout);
AssertInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE);
Node* getter =
LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
Node* getter_map = LoadMap(getter);
Node* instance_type = LoadMapInstanceType(getter_map);
// FunctionTemplateInfo getters are not supported yet.
GotoIf(Word32Equal(instance_type,
Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
if_bailout);
// Return undefined if the {getter} is not callable.
var_value->Bind(UndefinedConstant());
GotoIf(Word32Equal(Word32And(LoadMapBitField(getter_map),
Int32Constant(1 << Map::kIsCallable)),
Int32Constant(0)),
if_found_value);
// Call the accessor.
Callable callable = CodeFactory::Call(isolate());
Node* result = CallJS(callable, context, getter, receiver);
var_value->Bind(result);
Goto(if_found_value);
}
Node* value = CallGetterIfAccessor(var_value->value(), var_details.value(),
context, receiver, if_bailout);
var_value->Bind(value);
Goto(if_found_value);
}
}
@ -4884,12 +4899,10 @@ void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
Bind(&if_found_on_receiver);
{
Node* kind =
BitFieldDecode<PropertyDetails::KindField>(var_details.value());
// TODO(jkummerow): Support accessors without missing?
GotoUnless(Word32Equal(kind, Int32Constant(kData)), &slow);
Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
p->context, receiver, &slow);
IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
Return(var_value.value());
Return(value);
}
Bind(&slow);

View File

@ -788,6 +788,11 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* descriptors, compiler::Node* nof,
Label* if_found, Variable* var_name_index,
Label* if_not_found);
compiler::Node* CallGetterIfAccessor(compiler::Node* value,
compiler::Node* details,
compiler::Node* context,
compiler::Node* receiver,
Label* if_bailout);
void HandleLoadICHandlerCase(
const LoadICParameters* p, compiler::Node* handler, Label* miss,