Commit 1eadc764 authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Collect type feedback for 'new' in the bytecode handler

Collect type feedback in the bytecode handler for 'new' bytecode. The
current implementation does not collect allocation site feedback.

BUG=v8:4280, v8:4780
LOG=N

Review-Url: https://codereview.chromium.org/2153433002
Cr-Commit-Position: refs/heads/master@{#37862}
parent dcf8251e
...@@ -1206,7 +1206,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1206,7 +1206,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : argument count (not including receiver) // -- r0 : argument count (not including receiver)
// -- r3 : new target // -- r3 : new target
...@@ -1225,8 +1226,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1225,8 +1226,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// Push the arguments. // Push the arguments.
Generate_InterpreterPushArgs(masm, r2, r4, r5); Generate_InterpreterPushArgs(masm, r2, r4, r5);
// Call the constructor with r0, r1, and r3 unmodified. if (construct_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); // TODO(mythria): Change this when allocation site feedback is available.
// ConstructFunction initializes allocation site to undefined.
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with r0, r1, and r3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -1213,7 +1213,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1213,7 +1213,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : argument count (not including receiver) // -- x0 : argument count (not including receiver)
// -- x3 : new target // -- x3 : new target
...@@ -1244,8 +1245,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1244,8 +1245,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
__ Cmp(x6, x4); __ Cmp(x6, x4);
__ B(gt, &loop_header); __ B(gt, &loop_header);
// Call the constructor with x0, x1, and x3 unmodified. if (construct_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); // TODO(mythria): Change this when allocation site feedback is available.
// ConstructFunction initializes allocation site to undefined.
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with x0, x1, and x3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -4733,6 +4733,18 @@ Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode, ...@@ -4733,6 +4733,18 @@ Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
return Handle<Code>::null(); return Handle<Code>::null();
} }
Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
CallableType function_type) {
switch (function_type) {
case CallableType::kJSFunction:
return InterpreterPushArgsAndConstructFunction();
case CallableType::kAny:
return InterpreterPushArgsAndConstruct();
}
UNREACHABLE();
return Handle<Code>::null();
}
namespace { namespace {
class RelocatableArguments : public BuiltinArguments, public Relocatable { class RelocatableArguments : public BuiltinArguments, public Relocatable {
...@@ -5838,6 +5850,16 @@ void Builtins::Generate_InterpreterPushArgsAndTailCallFunction( ...@@ -5838,6 +5850,16 @@ void Builtins::Generate_InterpreterPushArgsAndTailCallFunction(
CallableType::kJSFunction); CallableType::kJSFunction);
} }
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(masm, CallableType::kAny);
}
void Builtins::Generate_InterpreterPushArgsAndConstructFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
masm, CallableType::kJSFunction);
}
void Builtins::Generate_MathMax(MacroAssembler* masm) { void Builtins::Generate_MathMax(MacroAssembler* masm) {
Generate_MathMaxMin(masm, MathMaxMinKind::kMax); Generate_MathMaxMin(masm, MathMaxMinKind::kMax);
} }
......
...@@ -129,6 +129,7 @@ namespace internal { ...@@ -129,6 +129,7 @@ namespace internal {
ASM(InterpreterPushArgsAndCall) \ ASM(InterpreterPushArgsAndCall) \
ASM(InterpreterPushArgsAndTailCall) \ ASM(InterpreterPushArgsAndTailCall) \
ASM(InterpreterPushArgsAndConstruct) \ ASM(InterpreterPushArgsAndConstruct) \
ASM(InterpreterPushArgsAndConstructFunction) \
ASM(InterpreterEnterBytecodeDispatch) \ ASM(InterpreterEnterBytecodeDispatch) \
\ \
/* Code life-cycle */ \ /* Code life-cycle */ \
...@@ -552,6 +553,7 @@ class Builtins { ...@@ -552,6 +553,7 @@ class Builtins {
Handle<Code> InterpreterPushArgsAndCall( Handle<Code> InterpreterPushArgsAndCall(
TailCallMode tail_call_mode, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny); CallableType function_type = CallableType::kAny);
Handle<Code> InterpreterPushArgsAndConstruct(CallableType function_type);
Code* builtin(Name name) { Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins // Code::cast cannot be used here since we access builtins
...@@ -593,6 +595,9 @@ class Builtins { ...@@ -593,6 +595,9 @@ class Builtins {
MacroAssembler* masm, TailCallMode tail_call_mode, MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type); CallableType function_type);
static void Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType function_type);
static void Generate_DatePrototype_GetField(MacroAssembler* masm, static void Generate_DatePrototype_GetField(MacroAssembler* masm,
int field_index); int field_index);
......
...@@ -758,7 +758,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -758,7 +758,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- edx : the new target // -- edx : the new target
...@@ -790,8 +791,17 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -790,8 +791,17 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// Re-push return address. // Re-push return address.
__ Push(ecx); __ Push(ecx);
// Call the constructor with unmodified eax, edi, ebi values. if (construct_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); // TODO(mythria): Change this when allocation site feedback is available.
// ConstructFunction initializes allocation site to undefined.
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with unmodified eax, edi, ebi values.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -1198,7 +1198,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1198,7 +1198,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argument count (not including receiver) // -- a0 : argument count (not including receiver)
// -- a3 : new target // -- a3 : new target
...@@ -1223,8 +1224,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1223,8 +1224,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
__ bind(&loop_check); __ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(t0)); __ Branch(&loop_header, gt, a2, Operand(t0));
// Call the constructor with a0, a1, and a3 unmodified. if (construct_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); // TODO(mythria): Change this when allocation site feedback is available.
// ConstructFunction initializes allocation site to undefined.
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with a0, a1, and a3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -1190,7 +1190,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1190,7 +1190,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argument count (not including receiver) // -- a0 : argument count (not including receiver)
// -- a3 : new target // -- a3 : new target
...@@ -1215,8 +1216,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1215,8 +1216,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
__ bind(&loop_check); __ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(t0)); __ Branch(&loop_header, gt, a2, Operand(t0));
// Call the constructor with a0, a1, and a3 unmodified. if (construct_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); // TODO(mythria): Change this when allocation site feedback is available.
// ConstructFunction initializes allocation site to undefined.
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with a0, a1, and a3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -840,7 +840,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -840,7 +840,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver) // -- rax : the number of arguments (not including the receiver)
// -- rdx : the new target (either the same as the constructor or // -- rdx : the new target (either the same as the constructor or
...@@ -862,8 +863,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -862,8 +863,16 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// Push return address in preparation for the tail-call. // Push return address in preparation for the tail-call.
__ PushReturnAddressFrom(kScratchRegister); __ PushReturnAddressFrom(kScratchRegister);
// Call the constructor (rax, rdx, rdi passed on). if (construct_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); // TODO(mythria): Change this when allocation site feedback is available.
// ConstructFunction initializes allocation site to undefined.
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor (rax, rdx, rdi passed on).
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -581,9 +581,11 @@ Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate, ...@@ -581,9 +581,11 @@ Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
// static // static
Callable CodeFactory::InterpreterPushArgsAndConstruct(Isolate* isolate) { Callable CodeFactory::InterpreterPushArgsAndConstruct(
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(), Isolate* isolate, CallableType function_type) {
InterpreterPushArgsAndConstructDescriptor(isolate)); return Callable(
isolate->builtins()->InterpreterPushArgsAndConstruct(function_type),
InterpreterPushArgsAndConstructDescriptor(isolate));
} }
......
...@@ -154,7 +154,8 @@ class CodeFactory final { ...@@ -154,7 +154,8 @@ class CodeFactory final {
static Callable InterpreterPushArgsAndCall( static Callable InterpreterPushArgsAndCall(
Isolate* isolate, TailCallMode tail_call_mode, Isolate* isolate, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny); CallableType function_type = CallableType::kAny);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate); static Callable InterpreterPushArgsAndConstruct(
Isolate* isolate, CallableType function_type = CallableType::kAny);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1); static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
}; };
......
...@@ -1060,12 +1060,17 @@ void BytecodeGraphBuilder::VisitNew() { ...@@ -1060,12 +1060,17 @@ void BytecodeGraphBuilder::VisitNew() {
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0); interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Slot index of 0 is used indicate no feedback slot is available. Assert
// the assumption that slot index 0 is never a valid feedback slot.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
Node* new_target = environment()->LookupAccumulator(); Node* new_target = environment()->LookupAccumulator();
Node* callee = environment()->LookupRegister(callee_reg); Node* callee = environment()->LookupRegister(callee_reg);
// TODO(turbofan): Pass the feedback here.
const Operator* call = javascript()->CallConstruct( const Operator* call =
static_cast<int>(arg_count) + 2, VectorSlotPair()); javascript()->CallConstruct(static_cast<int>(arg_count) + 2, feedback);
Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg, Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg,
arg_count + 2); arg_count + 2);
environment()->BindAccumulator(value, &states); environment()->BindAccumulator(value, &states);
......
...@@ -569,13 +569,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, ...@@ -569,13 +569,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
Register first_arg, Register first_arg,
size_t arg_count) { size_t arg_count,
int feedback_slot_id) {
if (!first_arg.is_valid()) { if (!first_arg.is_valid()) {
DCHECK_EQ(0u, arg_count); DCHECK_EQ(0u, arg_count);
first_arg = Register(0); first_arg = Register(0);
} }
Output(Bytecode::kNew, RegisterOperand(constructor), Output(Bytecode::kNew, RegisterOperand(constructor),
RegisterOperand(first_arg), UnsignedOperand(arg_count)); RegisterOperand(first_arg), UnsignedOperand(arg_count),
UnsignedOperand(feedback_slot_id));
return *this; return *this;
} }
......
...@@ -172,7 +172,7 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -172,7 +172,7 @@ class BytecodeArrayBuilder final : public ZoneObject {
// consecutive arguments starting at |first_arg| for the constuctor // consecutive arguments starting at |first_arg| for the constuctor
// invocation. // invocation.
BytecodeArrayBuilder& New(Register constructor, Register first_arg, BytecodeArrayBuilder& New(Register constructor, Register first_arg,
size_t arg_count); size_t arg_count, int feedback_slot);
// Call the runtime function with |function_id|. The first argument should be // Call the runtime function with |function_id|. The first argument should be
// in |first_arg| and all subsequent arguments should be in registers // in |first_arg| and all subsequent arguments should be in registers
......
...@@ -2527,7 +2527,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -2527,7 +2527,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
if (expr->CallFeedbackICSlot().IsInvalid()) { if (expr->CallFeedbackICSlot().IsInvalid()) {
DCHECK(call_type == Call::POSSIBLY_EVAL_CALL); DCHECK(call_type == Call::POSSIBLY_EVAL_CALL);
// Valid type feedback slots can only be greater than kReservedIndexCount. // Valid type feedback slots can only be greater than kReservedIndexCount.
// We use 0 to indicate an invalid slot it. Statically assert that 0 cannot // We use 0 to indicate an invalid slot id. Statically assert that 0 cannot
// be a valid slot id. // be a valid slot id.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
feedback_slot_index = 0; feedback_slot_index = 0;
...@@ -2562,7 +2562,13 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { ...@@ -2562,7 +2562,13 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// Call construct. // Call construct.
builder()->SetExpressionPosition(expr); builder()->SetExpressionPosition(expr);
builder()->New(constructor, first_arg, args->length()); // Valid type feedback slots can only be greater than kReservedIndexCount.
// Assert that 0 cannot be valid a valid slot id.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
// Type feedback is not necessary for super constructor calls. The type
// information can be inferred in most cases. Slot id 0 indicates type
// feedback is not required.
builder()->New(constructor, first_arg, args->length(), 0);
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
...@@ -2579,7 +2585,8 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) { ...@@ -2579,7 +2585,8 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
// constructor for CallNew. // constructor for CallNew.
builder() builder()
->LoadAccumulatorWithRegister(constructor) ->LoadAccumulatorWithRegister(constructor)
.New(constructor, first_arg, args->length()); .New(constructor, first_arg, args->length(),
feedback_index(expr->CallNewFeedbackSlot()));
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
......
...@@ -197,7 +197,7 @@ namespace interpreter { ...@@ -197,7 +197,7 @@ namespace interpreter {
\ \
/* New operator */ \ /* New operator */ \
V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \ V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \
OperandType::kMaybeReg, OperandType::kRegCount) \ OperandType::kMaybeReg, OperandType::kRegCount, OperandType::kIdx) \
\ \
/* Test Operators */ \ /* Test Operators */ \
V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \ V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \
......
...@@ -467,7 +467,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, ...@@ -467,7 +467,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
GotoIf(is_feedback_unavailable, &call); GotoIf(is_feedback_unavailable, &call);
// The checks. First, does rdi match the recorded monomorphic target? // The checks. First, does function match the recorded monomorphic target?
Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
Node* feedback_value = LoadWeakCellValue(feedback_element); Node* feedback_value = LoadWeakCellValue(feedback_element);
Node* is_monomorphic = WordEqual(function, feedback_value); Node* is_monomorphic = WordEqual(function, feedback_value);
...@@ -546,6 +546,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, ...@@ -546,6 +546,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
StoreFixedArrayElement(type_feedback_vector, call_count_slot, StoreFixedArrayElement(type_feedback_vector, call_count_slot,
SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER); SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
// TODO(mythria): Inline the weak cell creation/registration.
CreateWeakCellStub weak_cell_stub(isolate()); CreateWeakCellStub weak_cell_stub(isolate());
CallStub(weak_cell_stub.GetCallInterfaceDescriptor(), CallStub(weak_cell_stub.GetCallInterfaceDescriptor(),
HeapConstant(weak_cell_stub.GetCode()), context, HeapConstant(weak_cell_stub.GetCode()), context,
...@@ -603,11 +604,150 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context, ...@@ -603,11 +604,150 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
Node* new_target, Node* first_arg, Node* new_target, Node* first_arg,
Node* arg_count) { Node* arg_count, Node* slot_id,
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate()); Node* type_feedback_vector) {
Node* code_target = HeapConstant(callable.code()); Label call_construct(this), js_function(this), end(this);
return CallStub(callable.descriptor(), code_target, context, arg_count, Variable return_value(this, MachineRepresentation::kTagged);
new_target, constructor, first_arg);
// Slot id of 0 is used to indicate no typefeedback is available.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
GotoIf(is_feedback_unavailable, &call_construct);
// Check that the constructor is not a smi.
Node* is_smi = WordIsSmi(constructor);
GotoIf(is_smi, &call_construct);
// Check that constructor is a JSFunction.
Node* instance_type = LoadInstanceType(constructor);
Node* is_js_function =
WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
BranchIf(is_js_function, &js_function, &call_construct);
Bind(&js_function);
// Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a
// deferred block so that call_construct_function will be scheduled just
// after increment_count and in the fast path we can reduce one branch in the
// fast path.
Label increment_count(this), extra_checks(this),
call_construct_function(this);
Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
Node* feedback_value = LoadWeakCellValue(feedback_element);
Node* is_monomorphic = WordEqual(constructor, feedback_value);
BranchIf(is_monomorphic, &increment_count, &extra_checks);
Bind(&increment_count);
{
// Increment the call count.
Comment("increment call count");
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
Node* call_count =
LoadFixedArrayElement(type_feedback_vector, call_count_slot);
Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count,
SKIP_WRITE_BARRIER);
Goto(&call_construct_function);
}
Bind(&extra_checks);
{
Label mark_megamorphic(this), initialize(this),
check_weak_cell_cleared(this);
// Check if it is a megamorphic target
Comment("check if megamorphic");
Node* is_megamorphic = WordEqual(
feedback_element,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
GotoIf(is_megamorphic, &call_construct_function);
// Check if it is uninitialized.
Comment("check if uninitialized");
Node* is_uninitialized = WordEqual(
feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex));
BranchIf(is_uninitialized, &initialize, &check_weak_cell_cleared);
Bind(&check_weak_cell_cleared);
{
Comment("check if weak cell");
Node* is_weak_cell = WordEqual(LoadMap(feedback_element),
LoadRoot(Heap::kWeakCellMapRootIndex));
GotoUnless(is_weak_cell, &mark_megamorphic);
// If the weak cell is cleared, we have a new chance to become
// monomorphic.
Comment("check if weak cell is not cleared");
Node* is_smi = WordIsSmi(feedback_value);
BranchIf(is_smi, &initialize, &mark_megamorphic);
}
Bind(&initialize);
{
// Check that it is not the Array() function.
Comment("check it is not Array()");
Node* context_slot =
LoadFixedArrayElement(LoadNativeContext(context),
Int32Constant(Context::ARRAY_FUNCTION_INDEX));
Node* is_array_function = WordEqual(context_slot, constructor);
GotoIf(is_array_function, &mark_megamorphic);
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot,
SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
// TODO(mythria): Inline the weak cell creation/registration.
CreateWeakCellStub weak_cell_stub(isolate());
CallStub(weak_cell_stub.GetCallInterfaceDescriptor(),
HeapConstant(weak_cell_stub.GetCode()), context,
type_feedback_vector, SmiTag(slot_id), constructor);
Goto(&call_construct_function);
}
Bind(&mark_megamorphic);
{
// MegamorphicSentinel is an immortal immovable object so no write-barrier
// is needed.
Comment("transition to megamorphic");
DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
StoreFixedArrayElement(
type_feedback_vector, slot_id,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
SKIP_WRITE_BARRIER);
Goto(&call_construct_function);
}
}
Bind(&call_construct_function);
{
// TODO(mythria): Get allocation site feedback if available. Currently
// we do not collect allocation site feedback.
Comment("call using callConstructFunction");
Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), CallableType::kJSFunction);
return_value.Bind(CallStub(callable_function.descriptor(),
HeapConstant(callable_function.code()), context,
arg_count, new_target, constructor, first_arg));
Goto(&end);
}
Bind(&call_construct);
{
Comment("call using callConstruct builtin");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), CallableType::kAny);
Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context,
arg_count, new_target, constructor, first_arg));
Goto(&end);
}
Bind(&end);
return return_value.value();
} }
Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context, Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context,
......
...@@ -118,7 +118,9 @@ class InterpreterAssembler : public CodeStubAssembler { ...@@ -118,7 +118,9 @@ class InterpreterAssembler : public CodeStubAssembler {
compiler::Node* context, compiler::Node* context,
compiler::Node* new_target, compiler::Node* new_target,
compiler::Node* first_arg, compiler::Node* first_arg,
compiler::Node* arg_count); compiler::Node* arg_count,
compiler::Node* slot_id,
compiler::Node* type_feedback_vector);
// Call runtime function with |arg_count| arguments and the first argument // Call runtime function with |arg_count| arguments and the first argument
// located at |first_arg|. // located at |first_arg|.
......
...@@ -1285,9 +1285,11 @@ void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) { ...@@ -1285,9 +1285,11 @@ void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) {
Node* first_arg_reg = __ BytecodeOperandReg(1); Node* first_arg_reg = __ BytecodeOperandReg(1);
Node* first_arg = __ RegisterLocation(first_arg_reg); Node* first_arg = __ RegisterLocation(first_arg_reg);
Node* args_count = __ BytecodeOperandCount(2); Node* args_count = __ BytecodeOperandCount(2);
Node* slot_id = __ BytecodeOperandIdx(3);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* context = __ GetContext(); Node* context = __ GetContext();
Node* result = Node* result = __ CallConstruct(constructor, context, new_target, first_arg,
__ CallConstruct(constructor, context, new_target, first_arg, args_count); args_count, slot_id, type_feedback_vector);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
......
...@@ -134,12 +134,6 @@ ...@@ -134,12 +134,6 @@
# TODO(mythria,4780): Related to type feedback support for Array function. # TODO(mythria,4780): Related to type feedback support for Array function.
'test-feedback-vector/VectorCallFeedbackForArray': [PASS, NO_IGNITION], 'test-feedback-vector/VectorCallFeedbackForArray': [PASS, NO_IGNITION],
# TODO(mythria,4780): Related to type feedback support for constructor.
'test-feedback-vector/VectorConstructCounts': [PASS, NO_IGNITION],
'test-heap/WeakFunctionInConstructor': [PASS, NO_IGNITION],
'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [PASS, NO_IGNITION],
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [PASS, NO_IGNITION],
# TODO(mythria,4680): Lack of code-ageing in interpreter. # TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [PASS, NO_IGNITION], 'test-heap/Regress169209': [PASS, NO_IGNITION],
...@@ -416,12 +410,6 @@ ...@@ -416,12 +410,6 @@
# TODO(mythria,4780): Related to type feedback support for Array function. # TODO(mythria,4780): Related to type feedback support for Array function.
'test-feedback-vector/VectorCallFeedbackForArray': [FAIL], 'test-feedback-vector/VectorCallFeedbackForArray': [FAIL],
# TODO(mythria,4780): Related to type feedback support for constructor.
'test-feedback-vector/VectorConstructCounts': [FAIL],
'test-heap/WeakFunctionInConstructor': [FAIL],
'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [FAIL],
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
# TODO(mythria,4680): Lack of code-ageing in interpreter. # TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [FAIL], 'test-heap/Regress169209': [FAIL],
......
...@@ -16,12 +16,12 @@ snippet: " ...@@ -16,12 +16,12 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 11 bytecode array length: 12
bytecodes: [ bytecodes: [
/* 45 E> */ B(StackCheck), /* 45 E> */ B(StackCheck),
/* 50 S> */ B(LdrGlobal), U8(3), R(0), /* 50 S> */ B(LdrGlobal), U8(3), R(0),
B(Ldar), R(0), B(Ldar), R(0),
/* 57 E> */ B(New), R(0), R(0), U8(0), /* 57 E> */ B(New), R(0), R(0), U8(0), U8(1),
/* 68 S> */ B(Return), /* 68 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -37,14 +37,14 @@ snippet: " ...@@ -37,14 +37,14 @@ snippet: "
" "
frame size: 2 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 15 bytecode array length: 16
bytecodes: [ bytecodes: [
/* 58 E> */ B(StackCheck), /* 58 E> */ B(StackCheck),
/* 63 S> */ B(LdrGlobal), U8(3), R(0), /* 63 S> */ B(LdrGlobal), U8(3), R(0),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
B(Star), R(1), B(Star), R(1),
B(Ldar), R(0), B(Ldar), R(0),
/* 70 E> */ B(New), R(0), R(1), U8(1), /* 70 E> */ B(New), R(0), R(1), U8(1), U8(1),
/* 82 S> */ B(Return), /* 82 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -65,7 +65,7 @@ snippet: " ...@@ -65,7 +65,7 @@ snippet: "
" "
frame size: 4 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 23 bytecode array length: 24
bytecodes: [ bytecodes: [
/* 100 E> */ B(StackCheck), /* 100 E> */ B(StackCheck),
/* 105 S> */ B(LdrGlobal), U8(3), R(0), /* 105 S> */ B(LdrGlobal), U8(3), R(0),
...@@ -76,7 +76,7 @@ bytecodes: [ ...@@ -76,7 +76,7 @@ bytecodes: [
B(LdaSmi), U8(5), B(LdaSmi), U8(5),
B(Star), R(3), B(Star), R(3),
B(Ldar), R(0), B(Ldar), R(0),
/* 112 E> */ B(New), R(0), R(1), U8(3), /* 112 E> */ B(New), R(0), R(1), U8(3), U8(1),
/* 130 S> */ B(Return), /* 130 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -127,7 +127,7 @@ snippet: " ...@@ -127,7 +127,7 @@ snippet: "
" "
frame size: 5 frame size: 5
parameter count: 1 parameter count: 1
bytecode array length: 105 bytecode array length: 106
bytecodes: [ bytecodes: [
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
...@@ -147,7 +147,7 @@ bytecodes: [ ...@@ -147,7 +147,7 @@ bytecodes: [
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(4), B(Star), R(4),
/* 118 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), /* 118 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1),
/* 118 E> */ B(New), R(2), R(3), U8(1), /* 118 E> */ B(New), R(2), R(3), U8(1), U8(0),
B(Star), R(2), B(Star), R(2),
B(Ldar), R(this), B(Ldar), R(this),
B(JumpIfNotHole), U8(4), B(JumpIfNotHole), U8(4),
...@@ -195,7 +195,7 @@ snippet: " ...@@ -195,7 +195,7 @@ snippet: "
" "
frame size: 4 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 101 bytecode array length: 102
bytecodes: [ bytecodes: [
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
...@@ -213,7 +213,7 @@ bytecodes: [ ...@@ -213,7 +213,7 @@ bytecodes: [
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
/* 117 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), /* 117 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1),
/* 117 E> */ B(New), R(2), R(0), U8(0), /* 117 E> */ B(New), R(2), R(0), U8(0), U8(0),
B(Star), R(2), B(Star), R(2),
B(Ldar), R(this), B(Ldar), R(this),
B(JumpIfNotHole), U8(4), B(JumpIfNotHole), U8(4),
......
...@@ -195,7 +195,7 @@ snippet: " ...@@ -195,7 +195,7 @@ snippet: "
" "
frame size: 7 frame size: 7
parameter count: 1 parameter count: 1
bytecode array length: 73 bytecode array length: 74
bytecodes: [ bytecodes: [
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), U8(1), B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), U8(1),
B(PushContext), R(2), B(PushContext), R(2),
...@@ -225,7 +225,7 @@ bytecodes: [ ...@@ -225,7 +225,7 @@ bytecodes: [
B(Star), R(4), B(Star), R(4),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1),
B(Star), R(3), B(Star), R(3),
/* 94 E> */ B(New), R(3), R(0), U8(0), /* 94 E> */ B(New), R(3), R(0), U8(0), U8(3),
/* 103 S> */ B(Return), /* 103 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -165,8 +165,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -165,8 +165,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
// Emit new. // Emit new.
builder.New(reg, reg, 0); builder.New(reg, reg, 0, 1);
builder.New(wide, wide, 0); builder.New(wide, wide, 0, 1);
// Emit test operator invocations. // Emit test operator invocations.
builder.CompareOperation(Token::Value::EQ, reg) builder.CompareOperation(Token::Value::EQ, reg)
...@@ -456,7 +456,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { ...@@ -456,7 +456,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
// Ensure temporaries are used so not optimized away by the // Ensure temporaries are used so not optimized away by the
// register optimizer. // register optimizer.
builder.New(Register(locals + contexts), Register(locals + contexts), builder.New(Register(locals + contexts), Register(locals + contexts),
static_cast<size_t>(temps)); static_cast<size_t>(temps), 0);
} }
builder.Return(); builder.Return();
......
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