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 {
}
IC_BUILTIN(LoadIC)
IC_BUILTIN(LoadIC_Noninlined)
IC_BUILTIN(LoadIC_Uninitialized)
IC_BUILTIN(KeyedLoadIC)
IC_BUILTIN(LoadICTrampoline)
......
......@@ -472,6 +472,7 @@ class Isolate;
\
/* ICs */ \
TFS(LoadIC, LOAD_IC, kNoExtraICState, LoadWithVector, 1) \
TFS(LoadIC_Noninlined, BUILTIN, kNoExtraICState, LoadWithVector, 1) \
TFS(LoadICTrampoline, LOAD_IC, kNoExtraICState, Load, 1) \
TFS(KeyedLoadIC, KEYED_LOAD_IC, kNoExtraICState, LoadWithVector, 1) \
TFS(KeyedLoadICTrampoline, KEYED_LOAD_IC, kNoExtraICState, Load, 1) \
......
......@@ -56,6 +56,12 @@ Callable CodeFactory::LoadICInOptimizedCode(Isolate* isolate) {
LoadWithVectorDescriptor(isolate));
}
// static
Callable CodeFactory::LoadICInOptimizedCode_Noninlined(Isolate* isolate) {
return Callable(isolate->builtins()->LoadIC_Noninlined(),
LoadWithVectorDescriptor(isolate));
}
// static
Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) {
return Callable(
......
......@@ -40,6 +40,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable LoadIC(Isolate* isolate);
static Callable LoadIC_Uninitialized(Isolate* isolate);
static Callable LoadICInOptimizedCode(Isolate* isolate);
static Callable LoadICInOptimizedCode_Noninlined(Isolate* isolate);
static Callable LoadICProtoArray(Isolate* isolate, bool throw_if_nonexistent);
static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode);
static Callable LoadGlobalICInOptimizedCode(Isolate* isolate,
......
......@@ -2871,6 +2871,11 @@ Node* CodeStubAssembler::IsCallableMap(Node* map) {
Int32Constant(0));
}
Node* CodeStubAssembler::IsDeprecatedMap(Node* map) {
CSA_ASSERT(this, IsMap(map));
return IsSetWord32<Map::Deprecated>(LoadMapBitField3(map));
}
Node* CodeStubAssembler::IsCallable(Node* object) {
return IsCallableMap(LoadMap(object));
}
......
......@@ -697,6 +697,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsJSReceiverMap(Node* map);
Node* IsMap(Node* object);
Node* IsCallableMap(Node* map);
Node* IsDeprecatedMap(Node* map);
Node* IsCallable(Node* object);
Node* IsBoolean(Node* object);
Node* IsHeapNumber(Node* object);
......
This diff is collapsed.
......@@ -24,6 +24,7 @@ class AccessorAssembler : public CodeStubAssembler {
: CodeStubAssembler(state) {}
void GenerateLoadIC();
void GenerateLoadIC_Noninlined();
void GenerateLoadIC_Uninitialized();
void GenerateLoadField();
void GenerateLoadICTrampoline();
......@@ -76,6 +77,10 @@ class AccessorAssembler : public CodeStubAssembler {
ExitPoint* exit_point, Label* miss);
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:
struct StoreICParameters : public LoadICParameters {
StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
......@@ -94,7 +99,13 @@ class AccessorAssembler : public CodeStubAssembler {
private:
// 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_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 LoadICProtoArray(const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent);
......@@ -123,7 +134,7 @@ class AccessorAssembler : public CodeStubAssembler {
void HandleLoadICHandlerCase(
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,
Node* smi_handler, Label* miss,
......
......@@ -485,10 +485,12 @@ void Interpreter::DoMov(InterpreterAssembler* assembler) {
__ Dispatch();
}
void Interpreter::BuildLoadGlobal(int slot_operand_index,
void Interpreter::BuildLoadGlobalIC(int slot_operand_index,
int name_operand_index,
TypeofMode typeof_mode,
InterpreterAssembler* assembler) {
// Must be kept in sync with AccessorAssembler::LoadGlobalIC.
// Load the global via the LoadGlobalIC.
Node* feedback_vector = __ LoadFeedbackVector();
Node* feedback_slot = __ BytecodeOperandIdx(slot_operand_index);
......@@ -560,7 +562,7 @@ void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) {
static const int kNameOperandIndex = 0;
static const int kSlotOperandIndex = 1;
BuildLoadGlobal(kSlotOperandIndex, kNameOperandIndex, NOT_INSIDE_TYPEOF,
BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, NOT_INSIDE_TYPEOF,
assembler);
}
......@@ -572,7 +574,7 @@ void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) {
static const int kNameOperandIndex = 0;
static const int kSlotOperandIndex = 1;
BuildLoadGlobal(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF,
BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF,
assembler);
}
......@@ -777,7 +779,7 @@ void Interpreter::DoLdaLookupGlobalSlot(Runtime::FunctionId function_id,
? INSIDE_TYPEOF
: NOT_INSIDE_TYPEOF;
BuildLoadGlobal(kSlotOperandIndex, kNameOperandIndex, typeof_mode,
BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, typeof_mode,
assembler);
}
......@@ -839,25 +841,54 @@ void Interpreter::DoStaLookupSlotStrict(InterpreterAssembler* 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>
//
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
// constant pool entry <name_index>.
void Interpreter::DoLdaNamedProperty(InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_);
Node* code_target = __ HeapConstant(ic.code());
Node* register_index = __ BytecodeOperandReg(0);
Node* object = __ LoadRegister(register_index);
Node* constant_index = __ BytecodeOperandIdx(1);
Node* name = __ LoadConstantPoolEntry(constant_index);
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();
static const int kRecvOperandIndex = 0;
static const int kNameOperandIndex = 1;
static const int kSlotOperandIndex = 2;
BuildLoadIC(kRecvOperandIndex, kSlotOperandIndex, kNameOperandIndex,
assembler);
}
// KeyedLoadIC <object> <slot>
......
......@@ -147,9 +147,14 @@ class Interpreter {
void DoStaLookupSlot(LanguageMode language_mode,
InterpreterAssembler* assembler);
// Generates code to load a global.
void BuildLoadGlobal(int slot_operand_index, int name_operand_index,
TypeofMode typeof_mode, InterpreterAssembler* assembler);
// Generates code to load a global property.
void BuildLoadGlobalIC(int slot_operand_index, int name_operand_index,
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
// 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