Commit fd420203 authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Collect type feedback for calls in the bytecode handler

Collect type feedback in the call bytecode handler. The current
implementation only collects feedback for JS function objects. The other
objects and Array functions do not collect any feedback. They will be
marked Megamorphic.

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

Review-Url: https://codereview.chromium.org/2122183002
Cr-Commit-Position: refs/heads/master@{#37700}
parent 3861e513
......@@ -1195,7 +1195,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index,
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r2 : the address of the first argument to be pushed. Subsequent
......@@ -1213,9 +1214,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
Generate_InterpreterPushArgs(masm, r2, r3, r4);
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
if (function_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
}
}
// static
......
......@@ -1191,7 +1191,8 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x2 : the address of the first argument to be pushed. Subsequent
......@@ -1219,9 +1220,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ B(gt, &loop_header);
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
if (function_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
}
}
// static
......
......@@ -5932,12 +5932,21 @@ Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) {
return Handle<Code>::null();
}
Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode) {
Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
CallableType function_type) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return InterpreterPushArgsAndCall();
if (function_type == CallableType::kJSFunction) {
return InterpreterPushArgsAndCallFunction();
} else {
return InterpreterPushArgsAndCall();
}
case TailCallMode::kAllow:
return InterpreterPushArgsAndTailCall();
if (function_type == CallableType::kJSFunction) {
return InterpreterPushArgsAndTailCallFunction();
} else {
return InterpreterPushArgsAndTailCall();
}
}
UNREACHABLE();
return Handle<Code>::null();
......
......@@ -243,6 +243,8 @@ class CodeStubAssembler;
\
V(InterpreterEntryTrampoline, BUILTIN, kNoExtraICState) \
V(InterpreterMarkBaselineOnReturn, BUILTIN, kNoExtraICState) \
V(InterpreterPushArgsAndCallFunction, BUILTIN, kNoExtraICState) \
V(InterpreterPushArgsAndTailCallFunction, BUILTIN, kNoExtraICState) \
V(InterpreterPushArgsAndCall, BUILTIN, kNoExtraICState) \
V(InterpreterPushArgsAndTailCall, BUILTIN, kNoExtraICState) \
V(InterpreterPushArgsAndConstruct, BUILTIN, kNoExtraICState) \
......@@ -454,7 +456,9 @@ class Builtins {
Handle<Code> Call(ConvertReceiverMode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
Handle<Code> CallBoundFunction(TailCallMode tail_call_mode);
Handle<Code> InterpreterPushArgsAndCall(TailCallMode tail_call_mode);
Handle<Code> InterpreterPushArgsAndCall(
TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny);
Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins
......@@ -794,14 +798,26 @@ class Builtins {
static void Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm);
static void Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm);
static void Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm,
TailCallMode::kDisallow);
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, CallableType::kAny);
}
static void Generate_InterpreterPushArgsAndTailCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow);
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow,
CallableType::kAny);
}
static void Generate_InterpreterPushArgsAndCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, CallableType::kJSFunction);
}
static void Generate_InterpreterPushArgsAndTailCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow,
CallableType::kJSFunction);
}
static void Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode);
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type);
static void Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm);
#define DECLARE_CODE_AGE_BUILTIN_GENERATOR(C) \
......
......@@ -554,10 +554,11 @@ Callable CodeFactory::HasProperty(Isolate* isolate) {
// static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode) {
return Callable(
isolate->builtins()->InterpreterPushArgsAndCall(tail_call_mode),
InterpreterPushArgsAndCallDescriptor(isolate));
TailCallMode tail_call_mode,
CallableType function_type) {
return Callable(isolate->builtins()->InterpreterPushArgsAndCall(
tail_call_mode, function_type),
InterpreterPushArgsAndCallDescriptor(isolate));
}
......
......@@ -145,8 +145,9 @@ class CodeFactory final {
static Callable ConstructFunction(Isolate* isolate);
static Callable HasProperty(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode);
static Callable InterpreterPushArgsAndCall(
Isolate* isolate, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
};
......
......@@ -947,14 +947,15 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
FrameStateBeforeAndAfter states(this);
// TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver
// register has been loaded with null / undefined explicitly or we are sure it
// is not null / undefined.
ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny;
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
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));
......
......@@ -1098,6 +1098,20 @@ inline bool IsConstructable(FunctionKind kind, LanguageMode mode) {
return true;
}
enum class CallableType : unsigned { kJSFunction, kAny };
inline size_t hash_value(CallableType type) { return bit_cast<unsigned>(type); }
inline std::ostream& operator<<(std::ostream& os, CallableType function_type) {
switch (function_type) {
case CallableType::kJSFunction:
return os << "JSFunction";
case CallableType::kAny:
return os << "Any";
}
UNREACHABLE();
return os;
}
inline uint32_t ObjectHash(Address address) {
// All objects are at least pointer aligned, so we can remove the trailing
......
......@@ -731,7 +731,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- ebx : the address of the first argument to be pushed. Subsequent
......@@ -754,9 +755,17 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Call the target.
__ Push(edx); // Re-push return address.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
if (function_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
}
}
......
......@@ -154,7 +154,8 @@ class BytecodeArrayBuilder final : public ZoneObject {
// Call a JS function. The JSFunction or Callable to be called should be in
// |callable|, the receiver should be in |receiver_args| and all subsequent
// arguments should be in registers <receiver_args + 1> to
// <receiver_args + receiver_arg_count - 1>.
// <receiver_args + receiver_arg_count - 1>. Type feedback is recorded in
// the |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& Call(
Register callable, Register receiver_args, size_t receiver_arg_count,
int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow);
......
......@@ -2515,8 +2515,19 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
builder()->SetExpressionPosition(expr);
builder()->Call(callee, receiver, 1 + args->length(),
feedback_index(expr->CallFeedbackICSlot()),
int feedback_slot_index;
if (expr->CallFeedbackICSlot().IsInvalid()) {
DCHECK(call_type == Call::POSSIBLY_EVAL_CALL);
// Valid type feedback slots can only be greater than kReservedIndexCount.
// We use 0 to indicate an invalid slot it. Statically assert that 0 cannot
// be a valid slot id.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
feedback_slot_index = 0;
} else {
feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
}
builder()->Call(callee, receiver, 1 + args->length(), feedback_slot_index,
expr->tail_call_mode());
execution_result()->SetResultInAccumulator();
}
......
......@@ -438,11 +438,164 @@ void InterpreterAssembler::CallEpilogue() {
}
}
Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* first_arg, Node* arg_count,
Node* slot_id,
Node* type_feedback_vector,
TailCallMode tail_call_mode) {
// Static checks to assert it is safe to examine the type feedback element.
// We don't know that we have a weak cell. We might have a private symbol
// or an AllocationSite, but the memory is safe to examine.
// AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to
// FixedArray.
// WeakCell::kValueOffset - contains a JSFunction or Smi(0)
// Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not
// computed, meaning that it can't appear to be a pointer. If the low bit is
// 0, then hash is computed, but the 0 bit prevents the field from appearing
// to be a pointer.
STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
WeakCell::kValueOffset &&
WeakCell::kValueOffset == Symbol::kHashFieldSlot);
Variable return_value(this, MachineRepresentation::kTagged);
Label handle_monomorphic(this), extra_checks(this), end(this), call(this);
// Slot id of 0 is used to indicate no typefeedback is available. Call using
// call builtin.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
GotoIf(is_feedback_unavailable, &call);
// The checks. First, does rdi match the recorded monomorphic target?
Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
Node* feedback_value = LoadWeakCellValue(feedback_element);
Node* is_monomorphic = WordEqual(function, feedback_value);
BranchIf(is_monomorphic, &handle_monomorphic, &extra_checks);
Bind(&handle_monomorphic);
{
// The compare above could have been a SMI/SMI comparison. Guard against
// this convincing us that we have a monomorphic JSFunction.
Node* is_smi = WordIsSmi(function);
GotoIf(is_smi, &extra_checks);
// Increment the 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);
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction);
Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function);
return_value.Bind(ret_value);
Goto(&end);
}
Bind(&extra_checks);
{
Label check_initialized(this, Label::kDeferred), mark_megamorphic(this);
// Check if it is a megamorphic target
Node* is_megamorphic = WordEqual(
feedback_element,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
BranchIf(is_megamorphic, &call, &check_initialized);
Bind(&check_initialized);
{
Label possibly_monomorphic(this);
// Check if it is uninitialized.
Node* is_uninitialized = WordEqual(
feedback_element,
HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate())));
GotoUnless(is_uninitialized, &mark_megamorphic);
Node* is_smi = WordIsSmi(function);
GotoIf(is_smi, &mark_megamorphic);
// Check if function is an object of JSFunction type
Node* instance_type = LoadInstanceType(function);
Node* is_js_function =
WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
GotoUnless(is_js_function, &mark_megamorphic);
// Check that it is not the Array() function.
Node* context_slot =
LoadFixedArrayElement(LoadNativeContext(context),
Int32Constant(Context::ARRAY_FUNCTION_INDEX));
Node* is_array_function = WordEqual(context_slot, function);
GotoIf(is_array_function, &mark_megamorphic);
// Check if the function belongs to the same native context
Node* native_context = LoadNativeContext(
LoadObjectField(function, JSFunction::kContextOffset));
Node* is_same_native_context =
WordEqual(native_context, LoadNativeContext(context));
GotoUnless(is_same_native_context, &mark_megamorphic);
// Initialize it to a monomorphic target.
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);
CreateWeakCellStub weak_cell_stub(isolate());
CallStub(weak_cell_stub.GetCallInterfaceDescriptor(),
HeapConstant(weak_cell_stub.GetCode()), context,
type_feedback_vector, SmiTag(slot_id), function);
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction);
Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function);
return_value.Bind(ret_value);
Goto(&end);
}
Bind(&mark_megamorphic);
{
// Mark it as a megamorphic.
// MegamorphicSentinel is created as a part of Heap::InitialObjects
// and will not move during a GC. So it is safe to skip write barrier.
DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
StoreFixedArrayElement(
type_feedback_vector, slot_id,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
SKIP_WRITE_BARRIER);
Goto(&call);
}
}
Bind(&call);
{
// Call using call builtin.
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kAny);
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function);
return_value.Bind(ret_value);
Goto(&end);
}
Bind(&end);
return return_value.value();
}
Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* first_arg, Node* arg_count,
TailCallMode tail_call_mode) {
Callable callable =
CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode);
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kAny);
Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count,
first_arg, function);
......
......@@ -89,6 +89,18 @@ class InterpreterAssembler : public CodeStubAssembler {
// Load the TypeFeedbackVector for the current function.
compiler::Node* LoadTypeFeedbackVector();
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg|. Type feedback is collected in the
// slot at index |slot_id|.
compiler::Node* CallJSWithFeedback(compiler::Node* function,
compiler::Node* context,
compiler::Node* first_arg,
compiler::Node* arg_count,
compiler::Node* slot_id,
compiler::Node* type_feedback_vector,
TailCallMode tail_call_mode);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg|.
......
......@@ -1158,26 +1158,30 @@ void Interpreter::DoJSCall(InterpreterAssembler* assembler,
Node* receiver_args_count = __ BytecodeOperandCount(2);
Node* receiver_count = __ Int32Constant(1);
Node* args_count = __ Int32Sub(receiver_args_count, receiver_count);
Node* slot_id = __ BytecodeOperandIdx(3);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* context = __ GetContext();
// TODO(rmcilroy): Use the call type feedback slot to call via CallStub.
Node* result =
__ CallJS(function, context, receiver_arg, args_count, tail_call_mode);
__ CallJSWithFeedback(function, context, receiver_arg, args_count,
slot_id, type_feedback_vector, tail_call_mode);
__ SetAccumulator(result);
__ Dispatch();
}
// Call <callable> <receiver> <arg_count>
// Call <callable> <receiver> <arg_count> <feedback_slot_id>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
void Interpreter::DoCall(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kDisallow);
}
// TailCall <callable> <receiver> <arg_count>
// TailCall <callable> <receiver> <arg_count> <feedback_slot_id>
//
// Tail call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
void Interpreter::DoTailCall(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kAllow);
}
......
......@@ -99,7 +99,7 @@ class Interpreter {
// Generates code to perform a keyed property store via |ic|.
void DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler);
// Generates code to perform a JS call.
// Generates code to perform a JS call that collects type feedback.
void DoJSCall(InterpreterAssembler* assembler, TailCallMode tail_call_mode);
// Generates code to perform a runtime call.
......
......@@ -1181,7 +1181,8 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent
......@@ -1206,9 +1207,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ Branch(&loop_header, gt, a2, Operand(a3));
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
if (function_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
}
}
// static
......
......@@ -1171,7 +1171,8 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent
......@@ -1196,9 +1197,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ Branch(&loop_header, gt, a2, Operand(a3));
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
if (function_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
}
}
// static
......
......@@ -822,7 +822,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rbx : the address of the first argument to be pushed. Subsequent
......@@ -838,9 +839,17 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Call the target.
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
if (function_type == CallableType::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
}
}
// static
......
......@@ -133,15 +133,14 @@
# to be an issue when eagerly parsing.
'test-func-name-inference/ReturnAnonymousFunction': [PASS, NO_IGNITION],
# TODO(mythria,4780): Related to type feedback support for calls.
'test-feedback-vector/VectorCallICStates': [PASS, NO_IGNITION],
'test-feedback-vector/VectorCallCounts': [PASS, NO_IGNITION],
'test-compiler/FeedbackVectorPreservedAcrossRecompiles': [PASS, NO_IGNITION],
# TODO(mythria,4780): Related to type feedback support for Array function.
'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],
'test-heap/IncrementalMarkingPreservesMonomorphicCallIC': [PASS, NO_IGNITION],
'test-heap/CellsInOptimizedCodeAreWeak': [PASS, NO_IGNITION],
# TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [PASS, NO_IGNITION],
......@@ -424,15 +423,14 @@
# to be an issue when eagerly parsing.
'test-func-name-inference/ReturnAnonymousFunction': [FAIL],
# TODO(mythria,4780): Related to type feedback support for calls.
'test-feedback-vector/VectorCallICStates': [FAIL],
'test-feedback-vector/VectorCallCounts': [FAIL],
'test-compiler/FeedbackVectorPreservedAcrossRecompiles': [FAIL],
# TODO(mythria,4780): Related to type feedback support for Array function.
'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],
'test-heap/IncrementalMarkingPreservesMonomorphicCallIC': [FAIL],
'test-heap/CellsInOptimizedCodeAreWeak': [FAIL],
# TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [FAIL],
......
......@@ -798,10 +798,13 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
i::FeedbackVectorSpec feedback_spec(&zone);
i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
i::FeedbackVectorSlot call_slot = feedback_spec.AddCallICSlot();
Handle<i::TypeFeedbackVector> vector =
i::NewTypeFeedbackVector(isolate, &feedback_spec);
int slot_index = vector->GetIndex(slot);
int call_slot_index = -1;
call_slot_index = vector->GetIndex(call_slot);
Handle<i::String> name = factory->NewStringFromAsciiChecked("func");
name = factory->string_table()->LookupString(isolate, name);
......@@ -812,9 +815,12 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
0, 1);
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0))
.Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(0));
builder.Call(Register(0), builder.Parameter(0), 1, call_slot_index,
tail_call_mode);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
......@@ -832,9 +838,10 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
0, 1);
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0))
.Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(0));
builder.Call(Register(0), builder.Parameter(0), 1, call_slot_index,
tail_call_mode);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
......@@ -861,9 +868,12 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(Smi::FromInt(51))
.StoreAccumulatorInRegister(Register(2))
.LoadLiteral(Smi::FromInt(11))
.StoreAccumulatorInRegister(Register(3))
.Call(Register(0), Register(1), 3, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(3));
builder.Call(Register(0), Register(1), 3, call_slot_index, tail_call_mode);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
......@@ -905,9 +915,12 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(factory->NewStringFromAsciiChecked("i"))
.StoreAccumulatorInRegister(Register(10))
.LoadLiteral(factory->NewStringFromAsciiChecked("j"))
.StoreAccumulatorInRegister(Register(11))
.Call(Register(0), Register(1), 11, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(11));
builder.Call(Register(0), Register(1), 11, call_slot_index, tail_call_mode);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
......
......@@ -320,7 +320,10 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
// Verify that the feedback is still "gathered" despite a recompilation
// of the full code.
CHECK(f->IsOptimized());
CHECK(f->shared()->has_deoptimization_support());
// If the baseline code is bytecode, then it will not have deoptimization
// support. has_deoptimization_support() check is only required if the
// baseline code is from fullcodegen.
CHECK(f->shared()->has_deoptimization_support() || i::FLAG_ignition);
object = f->feedback_vector()->Get(slot_for_a);
CHECK(object->IsWeakCell() &&
WeakCell::cast(object)->value()->IsJSFunction());
......
......@@ -221,15 +221,33 @@ TEST(VectorCallICStates) {
// After a collection, state should remain GENERIC.
heap->CollectAllGarbage();
CHECK_EQ(GENERIC, nexus.StateFromFeedback());
}
TEST(VectorCallFeedbackForArray) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
// Make sure function f has a call that uses a type feedback slot.
CompileRun(
"function foo() { return 17; }"
"function f(a) { a(); } f(Array);");
Handle<JSFunction> f = GetFunction("f");
// There should be one IC.
Handle<TypeFeedbackVector> feedback_vector =
Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
FeedbackVectorSlot slot(0);
CallICNexus nexus(feedback_vector, slot);
// A call to Array is special, it contains an AllocationSite as feedback.
// Clear the IC manually in order to test this case.
nexus.Clear(f->shared()->code());
CompileRun("f(Array)");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
CHECK(nexus.GetFeedback()->IsAllocationSite());
heap->CollectAllGarbage();
// It should stay monomorphic even after a GC.
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
}
......@@ -255,16 +273,27 @@ TEST(VectorCallCounts) {
CompileRun("f(foo); f(foo);");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
CHECK_EQ(3, nexus.ExtractCallCount());
}
TEST(VectorConstructCounts) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
// Make sure function f has a call that uses a type feedback slot.
CompileRun(
"function Foo() {}"
"function f(a) { new a(); } f(Foo);");
f = GetFunction("f");
// There should be one IC.
feedback_vector = Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
FeedbackVectorSlot cslot(1);
Handle<JSFunction> f = GetFunction("f");
Handle<TypeFeedbackVector> feedback_vector =
Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
FeedbackVectorSlot slot(0);
CHECK(feedback_vector->Get(slot)->IsWeakCell());
CompileRun("f(Foo); f(Foo);");
FeedbackVectorSlot cslot(1);
CHECK(feedback_vector->Get(cslot)->IsSmi());
CHECK_EQ(3, Smi::cast(feedback_vector->Get(cslot))->value());
}
......
......@@ -30,7 +30,7 @@ function __f_3(x) {
var __v_1 = arguments;
__v_1[1000] = 123;
depth++;
if (depth > 3000) return;
if (depth > 2700) return;
function __f_4() {
++__v_1[0];
__f_3(0.5);
......
......@@ -110,10 +110,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
// Call operations.
builder.Call(reg, other, 1, 0)
.Call(reg, wide, 1, 0)
.TailCall(reg, other, 1, 0)
.TailCall(reg, wide, 1, 0)
builder.Call(reg, other, 0, 1)
.Call(reg, wide, 0, 1)
.TailCall(reg, other, 0, 1)
.TailCall(reg, wide, 0, 1)
.CallRuntime(Runtime::kIsArray, reg, 1)
.CallRuntime(Runtime::kIsArray, wide, 1)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other)
......
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