Commit 0bfabaf1 authored by jgruber's avatar jgruber Committed by Commit bot

[ic] Inline LoadIC into LdaNamedProperty bytecode handler

This inlines common LoadIC cases into the LdaNamedProperty bytecode
handler. Smi handlers resulting in constant/field loads for
monomorphic ICs omit frame construction. The same counts for the
polymorphic case as long as the target handler is in the first two
vector slots.

Other cases (megamorphic, uninitialized) call the new
LoadIC_Noninlined stub.

Local benchmarks show up to 6% improvement on Sunspider with --future.

BUG=v8:5917

Review-Url: https://codereview.chromium.org/2733563002
Cr-Commit-Position: refs/heads/master@{#43630}
parent 95d80867
...@@ -23,6 +23,7 @@ namespace internal { ...@@ -23,6 +23,7 @@ namespace internal {
} }
IC_BUILTIN(LoadIC) IC_BUILTIN(LoadIC)
IC_BUILTIN(LoadIC_Noninlined)
IC_BUILTIN(LoadIC_Uninitialized) IC_BUILTIN(LoadIC_Uninitialized)
IC_BUILTIN(KeyedLoadIC) IC_BUILTIN(KeyedLoadIC)
IC_BUILTIN(LoadICTrampoline) IC_BUILTIN(LoadICTrampoline)
......
...@@ -472,6 +472,7 @@ class Isolate; ...@@ -472,6 +472,7 @@ class Isolate;
\ \
/* ICs */ \ /* ICs */ \
TFS(LoadIC, LOAD_IC, kNoExtraICState, LoadWithVector, 1) \ TFS(LoadIC, LOAD_IC, kNoExtraICState, LoadWithVector, 1) \
TFS(LoadIC_Noninlined, BUILTIN, kNoExtraICState, LoadWithVector, 1) \
TFS(LoadICTrampoline, LOAD_IC, kNoExtraICState, Load, 1) \ TFS(LoadICTrampoline, LOAD_IC, kNoExtraICState, Load, 1) \
TFS(KeyedLoadIC, KEYED_LOAD_IC, kNoExtraICState, LoadWithVector, 1) \ TFS(KeyedLoadIC, KEYED_LOAD_IC, kNoExtraICState, LoadWithVector, 1) \
TFS(KeyedLoadICTrampoline, KEYED_LOAD_IC, kNoExtraICState, Load, 1) \ TFS(KeyedLoadICTrampoline, KEYED_LOAD_IC, kNoExtraICState, Load, 1) \
......
...@@ -56,6 +56,12 @@ Callable CodeFactory::LoadICInOptimizedCode(Isolate* isolate) { ...@@ -56,6 +56,12 @@ Callable CodeFactory::LoadICInOptimizedCode(Isolate* isolate) {
LoadWithVectorDescriptor(isolate)); LoadWithVectorDescriptor(isolate));
} }
// static
Callable CodeFactory::LoadICInOptimizedCode_Noninlined(Isolate* isolate) {
return Callable(isolate->builtins()->LoadIC_Noninlined(),
LoadWithVectorDescriptor(isolate));
}
// static // static
Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) { Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) {
return Callable( return Callable(
......
...@@ -40,6 +40,7 @@ class V8_EXPORT_PRIVATE CodeFactory final { ...@@ -40,6 +40,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable LoadIC(Isolate* isolate); static Callable LoadIC(Isolate* isolate);
static Callable LoadIC_Uninitialized(Isolate* isolate); static Callable LoadIC_Uninitialized(Isolate* isolate);
static Callable LoadICInOptimizedCode(Isolate* isolate); static Callable LoadICInOptimizedCode(Isolate* isolate);
static Callable LoadICInOptimizedCode_Noninlined(Isolate* isolate);
static Callable LoadICProtoArray(Isolate* isolate, bool throw_if_nonexistent); static Callable LoadICProtoArray(Isolate* isolate, bool throw_if_nonexistent);
static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode); static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode);
static Callable LoadGlobalICInOptimizedCode(Isolate* isolate, static Callable LoadGlobalICInOptimizedCode(Isolate* isolate,
......
...@@ -2871,6 +2871,11 @@ Node* CodeStubAssembler::IsCallableMap(Node* map) { ...@@ -2871,6 +2871,11 @@ Node* CodeStubAssembler::IsCallableMap(Node* map) {
Int32Constant(0)); Int32Constant(0));
} }
Node* CodeStubAssembler::IsDeprecatedMap(Node* map) {
CSA_ASSERT(this, IsMap(map));
return IsSetWord32<Map::Deprecated>(LoadMapBitField3(map));
}
Node* CodeStubAssembler::IsCallable(Node* object) { Node* CodeStubAssembler::IsCallable(Node* object) {
return IsCallableMap(LoadMap(object)); return IsCallableMap(LoadMap(object));
} }
......
...@@ -697,6 +697,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -697,6 +697,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsJSReceiverMap(Node* map); Node* IsJSReceiverMap(Node* map);
Node* IsMap(Node* object); Node* IsMap(Node* object);
Node* IsCallableMap(Node* map); Node* IsCallableMap(Node* map);
Node* IsDeprecatedMap(Node* map);
Node* IsCallable(Node* object); Node* IsCallable(Node* object);
Node* IsBoolean(Node* object); Node* IsBoolean(Node* object);
Node* IsHeapNumber(Node* object); Node* IsHeapNumber(Node* object);
......
This diff is collapsed.
...@@ -24,6 +24,7 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -24,6 +24,7 @@ class AccessorAssembler : public CodeStubAssembler {
: CodeStubAssembler(state) {} : CodeStubAssembler(state) {}
void GenerateLoadIC(); void GenerateLoadIC();
void GenerateLoadIC_Noninlined();
void GenerateLoadIC_Uninitialized(); void GenerateLoadIC_Uninitialized();
void GenerateLoadField(); void GenerateLoadField();
void GenerateLoadICTrampoline(); void GenerateLoadICTrampoline();
...@@ -76,6 +77,10 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -76,6 +77,10 @@ class AccessorAssembler : public CodeStubAssembler {
ExitPoint* exit_point, Label* miss); ExitPoint* exit_point, Label* miss);
void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point); void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point);
// Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
// construction on common paths.
void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
protected: protected:
struct StoreICParameters : public LoadICParameters { struct StoreICParameters : public LoadICParameters {
StoreICParameters(Node* context, Node* receiver, Node* name, Node* value, StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
...@@ -94,7 +99,13 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -94,7 +99,13 @@ class AccessorAssembler : public CodeStubAssembler {
private: private:
// Stub generation entry points. // Stub generation entry points.
// LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
// logic not inlined into Ignition bytecode handlers.
void LoadIC(const LoadICParameters* p); void LoadIC(const LoadICParameters* p);
void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
Node* feedback, Variable* var_handler,
Label* if_handler, Label* miss, ExitPoint* exit_point);
void LoadIC_Uninitialized(const LoadICParameters* p); void LoadIC_Uninitialized(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, Node* handler, void LoadICProtoArray(const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent); bool throw_reference_error_if_nonexistent);
...@@ -123,7 +134,7 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -123,7 +134,7 @@ class AccessorAssembler : public CodeStubAssembler {
void HandleLoadICHandlerCase( void HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss, const LoadICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements = kOnlyProperties); ExitPoint* exit_point, ElementSupport support_elements = kOnlyProperties);
void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
Node* smi_handler, Label* miss, Node* smi_handler, Label* miss,
......
...@@ -485,10 +485,12 @@ void Interpreter::DoMov(InterpreterAssembler* assembler) { ...@@ -485,10 +485,12 @@ void Interpreter::DoMov(InterpreterAssembler* assembler) {
__ Dispatch(); __ Dispatch();
} }
void Interpreter::BuildLoadGlobal(int slot_operand_index, void Interpreter::BuildLoadGlobalIC(int slot_operand_index,
int name_operand_index, int name_operand_index,
TypeofMode typeof_mode, TypeofMode typeof_mode,
InterpreterAssembler* assembler) { InterpreterAssembler* assembler) {
// Must be kept in sync with AccessorAssembler::LoadGlobalIC.
// Load the global via the LoadGlobalIC. // Load the global via the LoadGlobalIC.
Node* feedback_vector = __ LoadFeedbackVector(); Node* feedback_vector = __ LoadFeedbackVector();
Node* feedback_slot = __ BytecodeOperandIdx(slot_operand_index); Node* feedback_slot = __ BytecodeOperandIdx(slot_operand_index);
...@@ -560,7 +562,7 @@ void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) { ...@@ -560,7 +562,7 @@ void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) {
static const int kNameOperandIndex = 0; static const int kNameOperandIndex = 0;
static const int kSlotOperandIndex = 1; static const int kSlotOperandIndex = 1;
BuildLoadGlobal(kSlotOperandIndex, kNameOperandIndex, NOT_INSIDE_TYPEOF, BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, NOT_INSIDE_TYPEOF,
assembler); assembler);
} }
...@@ -572,7 +574,7 @@ void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) { ...@@ -572,7 +574,7 @@ void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) {
static const int kNameOperandIndex = 0; static const int kNameOperandIndex = 0;
static const int kSlotOperandIndex = 1; static const int kSlotOperandIndex = 1;
BuildLoadGlobal(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF, BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF,
assembler); assembler);
} }
...@@ -777,7 +779,7 @@ void Interpreter::DoLdaLookupGlobalSlot(Runtime::FunctionId function_id, ...@@ -777,7 +779,7 @@ void Interpreter::DoLdaLookupGlobalSlot(Runtime::FunctionId function_id,
? INSIDE_TYPEOF ? INSIDE_TYPEOF
: NOT_INSIDE_TYPEOF; : NOT_INSIDE_TYPEOF;
BuildLoadGlobal(kSlotOperandIndex, kNameOperandIndex, typeof_mode, BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, typeof_mode,
assembler); assembler);
} }
...@@ -839,25 +841,54 @@ void Interpreter::DoStaLookupSlotStrict(InterpreterAssembler* assembler) { ...@@ -839,25 +841,54 @@ void Interpreter::DoStaLookupSlotStrict(InterpreterAssembler* assembler) {
DoStaLookupSlot(LanguageMode::STRICT, assembler); DoStaLookupSlot(LanguageMode::STRICT, assembler);
} }
void Interpreter::BuildLoadIC(int recv_operand_index, int slot_operand_index,
int name_operand_index,
InterpreterAssembler* assembler) {
__ Comment("BuildLoadIC");
// Load vector and slot.
Node* feedback_vector = __ LoadFeedbackVector();
Node* feedback_slot = __ BytecodeOperandIdx(slot_operand_index);
Node* smi_slot = __ SmiTag(feedback_slot);
// Load receiver.
Node* register_index = __ BytecodeOperandReg(recv_operand_index);
Node* recv = __ LoadRegister(register_index);
// Load the name.
// TODO(jgruber): Not needed for monomorphic smi handler constant/field case.
Node* constant_index = __ BytecodeOperandIdx(name_operand_index);
Node* name = __ LoadConstantPoolEntry(constant_index);
Node* context = __ GetContext();
Label done(assembler);
Variable var_result(assembler, MachineRepresentation::kTagged);
ExitPoint exit_point(assembler, &done, &var_result);
AccessorAssembler::LoadICParameters params(context, recv, name, smi_slot,
feedback_vector);
AccessorAssembler accessor_asm(assembler->state());
accessor_asm.LoadIC_BytecodeHandler(&params, &exit_point);
__ Bind(&done);
{
__ SetAccumulator(var_result.value());
__ Dispatch();
}
}
// LdaNamedProperty <object> <name_index> <slot> // LdaNamedProperty <object> <name_index> <slot>
// //
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at // Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
// constant pool entry <name_index>. // constant pool entry <name_index>.
void Interpreter::DoLdaNamedProperty(InterpreterAssembler* assembler) { void Interpreter::DoLdaNamedProperty(InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_); static const int kRecvOperandIndex = 0;
Node* code_target = __ HeapConstant(ic.code()); static const int kNameOperandIndex = 1;
Node* register_index = __ BytecodeOperandReg(0); static const int kSlotOperandIndex = 2;
Node* object = __ LoadRegister(register_index);
Node* constant_index = __ BytecodeOperandIdx(1); BuildLoadIC(kRecvOperandIndex, kSlotOperandIndex, kNameOperandIndex,
Node* name = __ LoadConstantPoolEntry(constant_index); assembler);
Node* raw_slot = __ BytecodeOperandIdx(2);
Node* smi_slot = __ SmiTag(raw_slot);
Node* feedback_vector = __ LoadFeedbackVector();
Node* context = __ GetContext();
Node* result = __ CallStub(ic.descriptor(), code_target, context, object,
name, smi_slot, feedback_vector);
__ SetAccumulator(result);
__ Dispatch();
} }
// KeyedLoadIC <object> <slot> // KeyedLoadIC <object> <slot>
......
...@@ -147,9 +147,14 @@ class Interpreter { ...@@ -147,9 +147,14 @@ class Interpreter {
void DoStaLookupSlot(LanguageMode language_mode, void DoStaLookupSlot(LanguageMode language_mode,
InterpreterAssembler* assembler); InterpreterAssembler* assembler);
// Generates code to load a global. // Generates code to load a global property.
void BuildLoadGlobal(int slot_operand_index, int name_operand_index, void BuildLoadGlobalIC(int slot_operand_index, int name_operand_index,
TypeofMode typeof_mode, InterpreterAssembler* assembler); TypeofMode typeof_mode,
InterpreterAssembler* assembler);
// Generates code to load a property.
void BuildLoadIC(int recv_operand_index, int slot_operand_index,
int name_operand_index, InterpreterAssembler* assembler);
// Generates code to prepare the result for ForInPrepare. Cache data // Generates code to prepare the result for ForInPrepare. Cache data
// are placed into the consecutive series of registers starting at // are placed into the consecutive series of registers starting at
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment