[builtins] Sanitize the machinery around Construct calls.

There's no point in collecting feedback for super constructor calls,
because in all (interesting) cases we can gather (better) feedback from
other sources (i.e. via inlining or via using a LOAD_IC to get to the
[[Prototype]] of the target).  So CallConstructStub is now only used
for new Foo(...args) sites where we want to collect feedback in the
baseline compiler.  The optimizing compilers, Reflect.construct and
super constructor calls use the Construct builtin directly, which allows
us to remove some weird code from the CallConstructStub (and opens the
possibility for more code sharing with the CallICStub, maybe even going
for a ConstructICStub).

Also remove the 100% redundant HCallNew instruction, which is just a
wrapper for the Construct builtin anyway (indirectly via the
CallConstructStub).

Drive-by-fix: Drop unused has_function_cache bit on Code objects.

R=mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:4413, v8:4430
LOG=n

Review URL: https://codereview.chromium.org/1469793002

Cr-Commit-Position: refs/heads/master@{#32172}
This commit is contained in:
bmeurer 2015-11-23 02:34:04 -08:00 committed by Commit bot
parent c1e7c8d972
commit 374b6ea210
55 changed files with 309 additions and 719 deletions

View File

@ -1382,11 +1382,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector // Use undefined feedback vector
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ ldr(r1, MemOperand(fp, kFunctionOffset)); __ ldr(r1, MemOperand(fp, kFunctionOffset));
__ ldr(r4, MemOperand(fp, kNewTargetOffset)); __ ldr(r3, MemOperand(fp, kNewTargetOffset));
// Call the function. // Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); __ Call(masm->isolate()->builtins()->Construct(),
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); RelocInfo::CONSTRUCT_CALL);
// Leave internal frame. // Leave internal frame.
} }
@ -1655,22 +1655,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// ----------------------------------- // -----------------------------------
// Check if target has a [[Construct]] internal method. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(r1, &non_constructor); __ JumpIfSmi(r1, &non_constructor);
__ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r2, Operand(1 << Map::kIsConstructor));
__ b(eq, &non_constructor);
// Dispatch based on instance type. // Dispatch based on instance type.
__ CompareInstanceType(r4, r5, JS_FUNCTION_TYPE); __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(), __ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq); RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE)); __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
eq); eq);
// Check if target has a [[Construct]] internal method.
__ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r2, Operand(1 << Map::kIsConstructor));
__ b(eq, &non_constructor);
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.

View File

@ -2263,33 +2263,25 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
} }
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
bool is_super) {
// r0 : number of arguments to the construct function // r0 : number of arguments to the construct function
// r1 : the function to call // r1 : the function to call
// r2 : feedback vector // r2 : feedback vector
// r3 : slot in feedback vector (Smi) // r3 : slot in feedback vector (Smi)
// r4 : new target (for IsSuperConstructorCall)
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Number-of-arguments register must be smi-tagged to call out. // Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(r0); __ SmiTag(r0);
__ Push(r3, r2, r1, r0); __ Push(r3, r2, r1, r0);
if (is_super) {
__ Push(r4);
}
__ CallStub(stub); __ CallStub(stub);
if (is_super) {
__ Pop(r4);
}
__ Pop(r3, r2, r1, r0); __ Pop(r3, r2, r1, r0);
__ SmiUntag(r0); __ SmiUntag(r0);
} }
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a feedback vector slot. Cache states // Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and // are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic. // megamorphic.
@ -2297,7 +2289,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// r1 : the function to call // r1 : the function to call
// r2 : feedback vector // r2 : feedback vector
// r3 : slot in feedback vector (Smi) // r3 : slot in feedback vector (Smi)
// r4 : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function; Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
@ -2369,12 +2360,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Create an AllocationSite if we don't already have it, store it in the // Create an AllocationSite if we don't already have it, store it in the
// slot. // slot.
CreateAllocationSiteStub create_stub(masm->isolate()); CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, is_super); CallStubInRecordCallTarget(masm, &create_stub);
__ b(&done); __ b(&done);
__ bind(&not_array_function); __ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate()); CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done); __ bind(&done);
} }
@ -2384,7 +2375,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// r1 : the function to call // r1 : the function to call
// r2 : feedback vector // r2 : feedback vector
// r3 : slot in feedback vector (Smi, for RecordCallTarget) // r3 : slot in feedback vector (Smi, for RecordCallTarget)
// r4 : new target (for IsSuperConstructorCall)
Label non_function; Label non_function;
// Check that the function is not a smi. // Check that the function is not a smi.
@ -2393,28 +2383,22 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ CompareObjectType(r1, r5, r5, JS_FUNCTION_TYPE); __ CompareObjectType(r1, r5, r5, JS_FUNCTION_TYPE);
__ b(ne, &non_function); __ b(ne, &non_function);
if (RecordCallTarget()) { GenerateRecordCallTarget(masm);
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3));
Label feedback_register_initialized; Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into r2, or undefined. // Put the AllocationSite from the feedback vector into r2, or undefined.
__ ldr(r2, FieldMemOperand(r5, FixedArray::kHeaderSize)); __ ldr(r2, FieldMemOperand(r5, FixedArray::kHeaderSize));
__ ldr(r5, FieldMemOperand(r2, AllocationSite::kMapOffset)); __ ldr(r5, FieldMemOperand(r2, AllocationSite::kMapOffset));
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
__ b(eq, &feedback_register_initialized); __ b(eq, &feedback_register_initialized);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized); __ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(r2, r5); __ AssertUndefinedOrAllocationSite(r2, r5);
}
// Pass function as new target. // Pass function as new target.
if (IsSuperConstructorCall()) { __ mov(r3, r1);
__ mov(r3, r4);
} else {
__ mov(r3, r1);
}
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).

View File

@ -206,6 +206,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
} }
void ConstructTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r0 : number of arguments
// r1 : the target to call
// r3 : the new target
Register registers[] = {r1, r3, r0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific( void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
Register registers[] = {r2, r1, r0}; Register registers[] = {r2, r1, r0};

View File

@ -1372,11 +1372,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector // Use undefined feedback vector
__ LoadRoot(x2, Heap::kUndefinedValueRootIndex); __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
__ Ldr(x1, MemOperand(fp, kFunctionOffset)); __ Ldr(x1, MemOperand(fp, kFunctionOffset));
__ Ldr(x4, MemOperand(fp, kNewTargetOffset)); __ Ldr(x3, MemOperand(fp, kNewTargetOffset));
// Call the function. // Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); __ Call(masm->isolate()->builtins()->Construct(),
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); RelocInfo::CONSTRUCT_CALL);
// Leave internal frame. // Leave internal frame.
} }
@ -1648,21 +1648,22 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// ----------------------------------- // -----------------------------------
// Check if target has a [[Construct]] internal method. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(x1, &non_constructor); __ JumpIfSmi(x1, &non_constructor);
__ Ldr(x4, FieldMemOperand(x1, HeapObject::kMapOffset));
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
// Dispatch based on instance type. // Dispatch based on instance type.
__ CompareInstanceType(x4, x5, JS_FUNCTION_TYPE); __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(), __ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq); RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE); __ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
eq); eq);
// Check if target has a [[Construct]] internal method.
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.

View File

@ -2622,25 +2622,17 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
Register argc, Register function, Register argc, Register function,
Register feedback_vector, Register index, Register feedback_vector, Register index,
Register new_target, bool is_super) { Register new_target) {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
// Number-of-arguments register must be smi-tagged to call out. // Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(argc); __ SmiTag(argc);
if (is_super) { __ Push(argc, function, feedback_vector, index);
__ Push(argc, function, feedback_vector, index, new_target);
} else {
__ Push(argc, function, feedback_vector, index);
}
DCHECK(feedback_vector.Is(x2) && index.Is(x3)); DCHECK(feedback_vector.Is(x2) && index.Is(x3));
__ CallStub(stub); __ CallStub(stub);
if (is_super) { __ Pop(index, feedback_vector, function, argc);
__ Pop(new_target, index, feedback_vector, function, argc);
} else {
__ Pop(index, feedback_vector, function, argc);
}
__ SmiUntag(argc); __ SmiUntag(argc);
} }
@ -2649,8 +2641,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, Register argc,
Register function, Register function,
Register feedback_vector, Register index, Register feedback_vector, Register index,
Register new_target, Register scratch1, Register new_target, Register scratch1,
Register scratch2, Register scratch3, Register scratch2, Register scratch3) {
bool is_super) {
ASM_LOCATION("GenerateRecordCallTarget"); ASM_LOCATION("GenerateRecordCallTarget");
DCHECK(!AreAliased(scratch1, scratch2, scratch3, argc, function, DCHECK(!AreAliased(scratch1, scratch2, scratch3, argc, function,
feedback_vector, index, new_target)); feedback_vector, index, new_target));
@ -2660,7 +2651,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, Register argc,
// function : the function to call // function : the function to call
// feedback_vector : the feedback vector // feedback_vector : the feedback vector
// index : slot in feedback vector (smi) // index : slot in feedback vector (smi)
// new_target : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function; Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
@ -2736,13 +2726,13 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, Register argc,
// slot. // slot.
CreateAllocationSiteStub create_stub(masm->isolate()); CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, argc, function, CallStubInRecordCallTarget(masm, &create_stub, argc, function,
feedback_vector, index, new_target, is_super); feedback_vector, index, new_target);
__ B(&done); __ B(&done);
__ Bind(&not_array_function); __ Bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate()); CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, argc, function, CallStubInRecordCallTarget(masm, &weak_cell_stub, argc, function,
feedback_vector, index, new_target, is_super); feedback_vector, index, new_target);
__ Bind(&done); __ Bind(&done);
} }
@ -2753,7 +2743,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// x1 : the function to call // x1 : the function to call
// x2 : feedback vector // x2 : feedback vector
// x3 : slot in feedback vector (Smi, for RecordCallTarget) // x3 : slot in feedback vector (Smi, for RecordCallTarget)
// x4 : new target (for IsSuperConstructorCall)
Register function = x1; Register function = x1;
Label non_function; Label non_function;
@ -2764,28 +2753,21 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE, __ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE,
&non_function); &non_function);
if (RecordCallTarget()) { GenerateRecordCallTarget(masm, x0, function, x2, x3, x4, x5, x11, x12);
GenerateRecordCallTarget(masm, x0, function, x2, x3, x4, x5, x11, x12,
IsSuperConstructorCall());
__ Add(x5, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2)); __ Add(x5, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
Label feedback_register_initialized; Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into x2, or undefined. // Put the AllocationSite from the feedback vector into x2, or undefined.
__ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize)); __ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize));
__ Ldr(x5, FieldMemOperand(x2, AllocationSite::kMapOffset)); __ Ldr(x5, FieldMemOperand(x2, AllocationSite::kMapOffset));
__ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex, __ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex,
&feedback_register_initialized); &feedback_register_initialized);
__ LoadRoot(x2, Heap::kUndefinedValueRootIndex); __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized); __ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(x2, x5); __ AssertUndefinedOrAllocationSite(x2, x5);
}
if (IsSuperConstructorCall()) { __ Mov(x3, function);
__ Mov(x3, x4);
} else {
__ Mov(x3, function);
}
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).

View File

@ -221,6 +221,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
} }
void ConstructTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// x3: new target
// x1: target
// x0: number of arguments
Register registers[] = {x1, x3, x0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific( void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// x2: length // x2: length

View File

@ -304,6 +304,13 @@ Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
} }
// static
Callable CodeFactory::Construct(Isolate* isolate) {
return Callable(isolate->builtins()->Construct(),
ConstructTrampolineDescriptor(isolate));
}
// static // static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate) { Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsAndCall(), return Callable(isolate->builtins()->InterpreterPushArgsAndCall(),

View File

@ -103,6 +103,7 @@ class CodeFactory final {
ConvertReceiverMode mode = ConvertReceiverMode::kAny); ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable CallFunction( static Callable CallFunction(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny); Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable Construct(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(Isolate* isolate); static Callable InterpreterPushArgsAndCall(Isolate* isolate);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate); static Callable InterpreterPushArgsAndConstruct(Isolate* isolate);

View File

@ -886,12 +886,6 @@ void ArgumentsAccessStub::PrintName(std::ostream& os) const { // NOLINT
} }
void CallConstructStub::PrintName(std::ostream& os) const { // NOLINT
os << "CallConstructStub";
if (RecordCallTarget()) os << "_Recording";
}
void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT void ArrayConstructorStub::PrintName(std::ostream& os) const { // NOLINT
os << "ArrayConstructorStub"; os << "ArrayConstructorStub";
switch (argument_count()) { switch (argument_count()) {

View File

@ -1951,31 +1951,10 @@ class RegExpConstructResultStub final : public HydrogenCodeStub {
}; };
class CallConstructStub: public PlatformCodeStub { // TODO(bmeurer/mvstanton): Turn CallConstructStub into ConstructICStub.
class CallConstructStub final : public PlatformCodeStub {
public: public:
CallConstructStub(Isolate* isolate, CallConstructorFlags flags) explicit CallConstructStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
: PlatformCodeStub(isolate) {
minor_key_ = FlagBits::encode(flags);
}
void FinishCode(Handle<Code> code) override {
code->set_has_function_cache(RecordCallTarget());
}
private:
CallConstructorFlags flags() const { return FlagBits::decode(minor_key_); }
bool RecordCallTarget() const {
return (flags() & RECORD_CONSTRUCTOR_TARGET) != 0;
}
bool IsSuperConstructorCall() const {
return (flags() & SUPER_CONSTRUCTOR_CALL) != 0;
}
void PrintName(std::ostream& os) const override; // NOLINT
class FlagBits : public BitField<CallConstructorFlags, 0, 2> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(CallConstruct); DEFINE_CALL_INTERFACE_DESCRIPTOR(CallConstruct);
DEFINE_PLATFORM_CODE_STUB(CallConstruct, PlatformCodeStub); DEFINE_PLATFORM_CODE_STUB(CallConstruct, PlatformCodeStub);

View File

@ -540,22 +540,20 @@ void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
void JSGenericLowering::LowerJSCallConstruct(Node* node) { void JSGenericLowering::LowerJSCallConstruct(Node* node) {
CallConstructParameters const& p = CallConstructParametersOf(node->op()); CallConstructParameters const& p = CallConstructParametersOf(node->op());
int const arity = static_cast<int>(p.arity()); int const arg_count = static_cast<int>(p.arity() - 2);
// TODO(bmeurer): Use the Construct builtin here.
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
CallDescriptor* desc = Callable callable = CodeFactory::Construct(isolate());
Linkage::GetStubCallDescriptor(isolate(), zone(), d, arity - 1, flags); CallDescriptor* desc = Linkage::GetStubCallDescriptor(
Node* stub_code = jsgraph()->HeapConstant(stub.GetCode()); isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
Node* target = NodeProperties::GetValueInput(node, 0); Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* new_target = NodeProperties::GetValueInput(node, arity - 1); Node* stub_arity = jsgraph()->Int32Constant(arg_count);
node->RemoveInput(arity - 1); // Drop new target. Node* new_target = node->InputAt(arg_count + 1);
Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(arg_count + 1); // Drop new target.
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 1, jsgraph()->Int32Constant(arity - 2)); node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 2, target); node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 3, new_target); node->InsertInput(zone(), 4, receiver);
node->InsertInput(zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(node, common()->Call(desc)); NodeProperties::ChangeOp(node, common()->Call(desc));
} }

View File

@ -298,13 +298,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
} }
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) { void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= "); stream->Add("= ");
constructor()->PrintTo(stream); constructor()->PrintTo(stream);
@ -1213,14 +1206,6 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
} }
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), r1);
LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, r0), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), cp); LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), r1); LOperand* constructor = UseFixed(instr->constructor(), r1);

View File

@ -33,7 +33,6 @@ class LCodeGen;
V(CallJSFunction) \ V(CallJSFunction) \
V(CallWithDescriptor) \ V(CallWithDescriptor) \
V(CallFunction) \ V(CallFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -1893,25 +1892,6 @@ class LCallFunction final : public LTemplateInstruction<1, 2, 2> {
}; };
class LCallNew final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> { class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public: public:
LCallNewArray(LOperand* context, LOperand* constructor) { LCallNewArray(LOperand* context, LOperand* constructor) {

View File

@ -3843,19 +3843,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
} }
void LCodeGen::DoCallNew(LCallNew* instr) {
DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(ToRegister(instr->constructor()).is(r1));
DCHECK(ToRegister(instr->result()).is(r0));
__ mov(r0, Operand(instr->arity()));
// No cell in r2 for construct type feedback in optimized code
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
}
void LCodeGen::DoCallNewArray(LCallNewArray* instr) { void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(ToRegister(instr->constructor()).is(r1)); DCHECK(ToRegister(instr->constructor()).is(r1));

View File

@ -82,13 +82,6 @@ void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
} }
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) { void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= "); stream->Add("= ");
constructor()->PrintTo(stream); constructor()->PrintTo(stream);
@ -1076,15 +1069,6 @@ LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
} }
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), cp);
// The call to CallConstructStub will expect the constructor to be in x1.
LOperand* constructor = UseFixed(instr->constructor(), x1);
LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, x0), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), cp); LOperand* context = UseFixed(instr->context(), cp);
// The call to ArrayConstructCode will expect the constructor to be in x1. // The call to ArrayConstructCode will expect the constructor to be in x1.

View File

@ -35,7 +35,6 @@ class LCodeGen;
V(Branch) \ V(Branch) \
V(CallFunction) \ V(CallFunction) \
V(CallJSFunction) \ V(CallJSFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -851,25 +850,6 @@ class LCallFunction final : public LTemplateInstruction<1, 2, 2> {
}; };
class LCallNew final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> { class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public: public:
LCallNewArray(LOperand* context, LOperand* constructor) { LCallNewArray(LOperand* context, LOperand* constructor) {

View File

@ -396,23 +396,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
} }
void LCodeGen::DoCallNew(LCallNew* instr) {
DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(instr->IsMarkedAsCall());
DCHECK(ToRegister(instr->constructor()).is(x1));
__ Mov(x0, instr->arity());
// No cell in x2 for construct type feedback in optimized code.
__ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
DCHECK(ToRegister(instr->result()).is(x0));
}
void LCodeGen::DoCallNewArray(LCallNewArray* instr) { void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
DCHECK(instr->IsMarkedAsCall()); DCHECK(instr->IsMarkedAsCall());
DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->context()).is(cp));

View File

@ -776,7 +776,6 @@ bool HInstruction::CanDeoptimize() {
case HValue::kBlockEntry: case HValue::kBlockEntry:
case HValue::kBoundsCheckBaseIndexInformation: case HValue::kBoundsCheckBaseIndexInformation:
case HValue::kCallFunction: case HValue::kCallFunction:
case HValue::kCallNew:
case HValue::kCallNewArray: case HValue::kCallNewArray:
case HValue::kCallStub: case HValue::kCallStub:
case HValue::kCapturedObject: case HValue::kCapturedObject:

View File

@ -62,7 +62,6 @@ class LChunkBuilder;
V(CallWithDescriptor) \ V(CallWithDescriptor) \
V(CallJSFunction) \ V(CallJSFunction) \
V(CallFunction) \ V(CallFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -2429,21 +2428,6 @@ class HCallFunction final : public HBinaryCall {
}; };
class HCallNew final : public HBinaryCall {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
HValue* context() { return first(); }
HValue* constructor() { return second(); }
DECLARE_CONCRETE_INSTRUCTION(CallNew)
private:
HCallNew(HValue* context, HValue* constructor, int argument_count)
: HBinaryCall(context, constructor, argument_count) {}
};
class HCallNewArray final : public HBinaryCall { class HCallNewArray final : public HBinaryCall {
public: public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int, DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,

View File

@ -9993,18 +9993,21 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
instr = prev_instr; instr = prev_instr;
} while (instr != check); } while (instr != check);
environment()->SetExpressionStackAt(receiver_index, function); environment()->SetExpressionStackAt(receiver_index, function);
HInstruction* call =
PreProcessCall(New<HCallNew>(function, argument_count));
return ast_context()->ReturnInstruction(call, expr->id());
} else { } else {
// The constructor function is both an operand to the instruction and an // The constructor function is both an operand to the instruction and an
// argument to the construct call. // argument to the construct call.
if (TryHandleArrayCallNew(expr, function)) return; if (TryHandleArrayCallNew(expr, function)) return;
HInstruction* call =
PreProcessCall(New<HCallNew>(function, argument_count));
return ast_context()->ReturnInstruction(call, expr->id());
} }
HValue* arity = Add<HConstant>(argument_count - 1);
HValue* op_vals[] = {context(), function, function, arity};
Callable callable = CodeFactory::Construct(isolate());
HConstant* stub = Add<HConstant>(callable.code());
PushArgumentsFromEnvironment(argument_count);
HInstruction* construct =
New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
Vector<HValue*>(op_vals, arraysize(op_vals)));
return ast_context()->ReturnInstruction(construct, expr->id());
} }

View File

@ -3781,19 +3781,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
} }
void LCodeGen::DoCallNew(LCallNew* instr) {
DCHECK(ToRegister(instr->context()).is(esi));
DCHECK(ToRegister(instr->constructor()).is(edi));
DCHECK(ToRegister(instr->result()).is(eax));
// No cell in ebx for construct type feedback in optimized code
__ mov(ebx, isolate()->factory()->undefined_value());
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
__ Move(eax, Immediate(instr->arity()));
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
}
void LCodeGen::DoCallNewArray(LCallNewArray* instr) { void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
DCHECK(ToRegister(instr->context()).is(esi)); DCHECK(ToRegister(instr->context()).is(esi));
DCHECK(ToRegister(instr->constructor()).is(edi)); DCHECK(ToRegister(instr->constructor()).is(edi));

View File

@ -319,15 +319,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
} }
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
context()->PrintTo(stream);
stream->Add(" ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) { void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= "); stream->Add("= ");
context()->PrintTo(stream); context()->PrintTo(stream);
@ -1252,14 +1243,6 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
} }
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* constructor = UseFixed(instr->constructor(), edi);
LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), esi); LOperand* context = UseFixed(instr->context(), esi);
LOperand* constructor = UseFixed(instr->constructor(), edi); LOperand* constructor = UseFixed(instr->constructor(), edi);

View File

@ -37,7 +37,6 @@ class LCodeGen;
V(CallJSFunction) \ V(CallJSFunction) \
V(CallWithDescriptor) \ V(CallWithDescriptor) \
V(CallFunction) \ V(CallFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -1906,25 +1905,6 @@ class LCallFunction final : public LTemplateInstruction<1, 2, 2> {
}; };
class LCallNew final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> { class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public: public:
LCallNewArray(LOperand* context, LOperand* constructor) { LCallNewArray(LOperand* context, LOperand* constructor) {

View File

@ -3818,19 +3818,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
} }
void LCodeGen::DoCallNew(LCallNew* instr) {
DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(ToRegister(instr->constructor()).is(a1));
DCHECK(ToRegister(instr->result()).is(v0));
__ li(a0, Operand(instr->arity()));
// No cell in a2 for construct type feedback in optimized code
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
}
void LCodeGen::DoCallNewArray(LCallNewArray* instr) { void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(ToRegister(instr->constructor()).is(a1)); DCHECK(ToRegister(instr->constructor()).is(a1));

View File

@ -305,13 +305,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
} }
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) { void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= "); stream->Add("= ");
constructor()->PrintTo(stream); constructor()->PrintTo(stream);
@ -1221,14 +1214,6 @@ LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
} }
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), a1);
LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, v0), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), cp); LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), a1); LOperand* constructor = UseFixed(instr->constructor(), a1);

View File

@ -33,7 +33,6 @@ class LCodeGen;
V(CallJSFunction) \ V(CallJSFunction) \
V(CallWithDescriptor) \ V(CallWithDescriptor) \
V(CallFunction) \ V(CallFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -1856,25 +1855,6 @@ class LCallFunction final : public LTemplateInstruction<1, 2, 2> {
}; };
class LCallNew final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> { class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public: public:
LCallNewArray(LOperand* context, LOperand* constructor) { LCallNewArray(LOperand* context, LOperand* constructor) {

View File

@ -4006,19 +4006,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
} }
void LCodeGen::DoCallNew(LCallNew* instr) {
DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(ToRegister(instr->constructor()).is(a1));
DCHECK(ToRegister(instr->result()).is(v0));
__ li(a0, Operand(instr->arity()));
// No cell in a2 for construct type feedback in optimized code
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
}
void LCodeGen::DoCallNewArray(LCallNewArray* instr) { void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->context()).is(cp));
DCHECK(ToRegister(instr->constructor()).is(a1)); DCHECK(ToRegister(instr->constructor()).is(a1));

View File

@ -305,13 +305,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
} }
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) { void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= "); stream->Add("= ");
constructor()->PrintTo(stream); constructor()->PrintTo(stream);
@ -1221,14 +1214,6 @@ LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
} }
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), a1);
LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, v0), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), cp); LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), a1); LOperand* constructor = UseFixed(instr->constructor(), a1);

View File

@ -35,7 +35,6 @@ class LCodeGen;
V(CallJSFunction) \ V(CallJSFunction) \
V(CallWithDescriptor) \ V(CallWithDescriptor) \
V(CallFunction) \ V(CallFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -1918,25 +1917,6 @@ class LCallFunction final : public LTemplateInstruction<1, 2, 2> {
}; };
class LCallNew final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> { class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public: public:
LCallNewArray(LOperand* context, LOperand* constructor) { LCallNewArray(LOperand* context, LOperand* constructor) {

View File

@ -3870,19 +3870,6 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
} }
void LCodeGen::DoCallNew(LCallNew* instr) {
DCHECK(ToRegister(instr->context()).is(rsi));
DCHECK(ToRegister(instr->constructor()).is(rdi));
DCHECK(ToRegister(instr->result()).is(rax));
__ Set(rax, instr->arity());
// No cell in ebx for construct type feedback in optimized code
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
}
void LCodeGen::DoCallNewArray(LCallNewArray* instr) { void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
DCHECK(ToRegister(instr->context()).is(rsi)); DCHECK(ToRegister(instr->context()).is(rsi));
DCHECK(ToRegister(instr->constructor()).is(rdi)); DCHECK(ToRegister(instr->constructor()).is(rdi));

View File

@ -311,13 +311,6 @@ void LInvokeFunction::PrintDataTo(StringStream* stream) {
} }
void LCallNew::PrintDataTo(StringStream* stream) {
stream->Add("= ");
constructor()->PrintTo(stream);
stream->Add(" #%d / ", arity());
}
void LCallNewArray::PrintDataTo(StringStream* stream) { void LCallNewArray::PrintDataTo(StringStream* stream) {
stream->Add("= "); stream->Add("= ");
constructor()->PrintTo(stream); constructor()->PrintTo(stream);
@ -1231,14 +1224,6 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
} }
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* constructor = UseFixed(instr->constructor(), rdi);
LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, rax), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
LOperand* context = UseFixed(instr->context(), rsi); LOperand* context = UseFixed(instr->context(), rsi);
LOperand* constructor = UseFixed(instr->constructor(), rdi); LOperand* constructor = UseFixed(instr->constructor(), rdi);

View File

@ -33,7 +33,6 @@ class LCodeGen;
V(CallJSFunction) \ V(CallJSFunction) \
V(CallWithDescriptor) \ V(CallWithDescriptor) \
V(CallFunction) \ V(CallFunction) \
V(CallNew) \
V(CallNewArray) \ V(CallNewArray) \
V(CallRuntime) \ V(CallRuntime) \
V(CallStub) \ V(CallStub) \
@ -1879,25 +1878,6 @@ class LCallFunction final : public LTemplateInstruction<1, 2, 2> {
}; };
class LCallNew final : public LTemplateInstruction<1, 2, 0> {
public:
LCallNew(LOperand* context, LOperand* constructor) {
inputs_[0] = context;
inputs_[1] = constructor;
}
LOperand* context() { return inputs_[0]; }
LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
void PrintDataTo(StringStream* stream) override;
int arity() const { return hydrogen()->argument_count() - 1; }
};
class LCallNewArray final : public LTemplateInstruction<1, 2, 0> { class LCallNewArray final : public LTemplateInstruction<1, 2, 0> {
public: public:
LCallNewArray(LOperand* context, LOperand* constructor) { LCallNewArray(LOperand* context, LOperand* constructor) {

View File

@ -3071,7 +3071,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ EmitLoadTypeFeedbackVector(r2); __ EmitLoadTypeFeedbackVector(r2);
__ mov(r3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot()))); __ mov(r3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); CallConstructStub stub(isolate());
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
PrepareForBailoutForId(expr->ReturnId(), TOS_REG); PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
// Restore context register. // Restore context register.
@ -3099,20 +3099,15 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
// constructor invocation. // constructor invocation.
SetConstructCallPosition(expr, arg_count); SetConstructCallPosition(expr, arg_count);
// Load new target into r4. // Load new target into r3.
VisitForAccumulatorValue(super_call_ref->new_target_var()); VisitForAccumulatorValue(super_call_ref->new_target_var());
__ mov(r4, result_register()); __ mov(r3, result_register());
// Load function and argument count into r1 and r0. // Load function and argument count into r1 and r0.
__ mov(r0, Operand(arg_count)); __ mov(r0, Operand(arg_count));
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code. __ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
__ EmitLoadTypeFeedbackVector(r2);
__ mov(r3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);

View File

@ -2777,7 +2777,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ EmitLoadTypeFeedbackVector(x2); __ EmitLoadTypeFeedbackVector(x2);
__ Mov(x3, SmiFromSlot(expr->CallNewFeedbackSlot())); __ Mov(x3, SmiFromSlot(expr->CallNewFeedbackSlot()));
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); CallConstructStub stub(isolate());
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
PrepareForBailoutForId(expr->ReturnId(), TOS_REG); PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
// Restore context register. // Restore context register.
@ -2805,20 +2805,15 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
// constructor invocation. // constructor invocation.
SetConstructCallPosition(expr, arg_count); SetConstructCallPosition(expr, arg_count);
// Load new target into x4. // Load new target into x3.
VisitForAccumulatorValue(super_call_ref->new_target_var()); VisitForAccumulatorValue(super_call_ref->new_target_var());
__ Mov(x4, result_register()); __ Mov(x3, result_register());
// Load function and argument count into x1 and x0. // Load function and argument count into x1 and x0.
__ Mov(x0, arg_count); __ Mov(x0, arg_count);
__ Peek(x1, arg_count * kXRegSize); __ Peek(x1, arg_count * kXRegSize);
// Record call targets in unoptimized code. __ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
__ EmitLoadTypeFeedbackVector(x2);
__ Mov(x3, SmiFromSlot(expr->CallFeedbackSlot()));
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);

View File

@ -2954,7 +2954,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ EmitLoadTypeFeedbackVector(ebx); __ EmitLoadTypeFeedbackVector(ebx);
__ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot()))); __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); CallConstructStub stub(isolate());
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
PrepareForBailoutForId(expr->ReturnId(), TOS_REG); PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
// Restore context register. // Restore context register.
@ -2982,20 +2982,15 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
// constructor invocation. // constructor invocation.
SetConstructCallPosition(expr, arg_count); SetConstructCallPosition(expr, arg_count);
// Load new target into ecx. // Load new target into edx.
VisitForAccumulatorValue(super_call_ref->new_target_var()); VisitForAccumulatorValue(super_call_ref->new_target_var());
__ mov(ecx, result_register()); __ mov(edx, result_register());
// Load function and argument count into edi and eax. // Load function and argument count into edi and eax.
__ Move(eax, Immediate(arg_count)); __ Move(eax, Immediate(arg_count));
__ mov(edi, Operand(esp, arg_count * kPointerSize)); __ mov(edi, Operand(esp, arg_count * kPointerSize));
// Record call targets in unoptimized code. __ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
__ EmitLoadTypeFeedbackVector(ebx);
__ mov(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot())));
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);

View File

@ -3062,7 +3062,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ EmitLoadTypeFeedbackVector(a2); __ EmitLoadTypeFeedbackVector(a2);
__ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot()))); __ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); CallConstructStub stub(isolate());
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
PrepareForBailoutForId(expr->ReturnId(), TOS_REG); PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
// Restore context register. // Restore context register.
@ -3090,20 +3090,15 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
// constructor invocation. // constructor invocation.
SetConstructCallPosition(expr, arg_count); SetConstructCallPosition(expr, arg_count);
// Load new target into t0. // Load new target into a3.
VisitForAccumulatorValue(super_call_ref->new_target_var()); VisitForAccumulatorValue(super_call_ref->new_target_var());
__ mov(t0, result_register()); __ mov(a3, result_register());
// Load function and argument count into a1 and a0. // Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count)); __ li(a0, Operand(arg_count));
__ lw(a1, MemOperand(sp, arg_count * kPointerSize)); __ lw(a1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code. __ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
__ EmitLoadTypeFeedbackVector(a2);
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);

View File

@ -3066,7 +3066,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ EmitLoadTypeFeedbackVector(a2); __ EmitLoadTypeFeedbackVector(a2);
__ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot()))); __ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); CallConstructStub stub(isolate());
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
PrepareForBailoutForId(expr->ReturnId(), TOS_REG); PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
// Restore context register. // Restore context register.
@ -3094,20 +3094,15 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
// constructor invocation. // constructor invocation.
SetConstructCallPosition(expr, arg_count); SetConstructCallPosition(expr, arg_count);
// Load new target into a4. // Load new target into a3.
VisitForAccumulatorValue(super_call_ref->new_target_var()); VisitForAccumulatorValue(super_call_ref->new_target_var());
__ mov(a4, result_register()); __ mov(a3, result_register());
// Load function and argument count into a1 and a0. // Load function and argument count into a1 and a0.
__ li(a0, Operand(arg_count)); __ li(a0, Operand(arg_count));
__ ld(a1, MemOperand(sp, arg_count * kPointerSize)); __ ld(a1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code. __ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
__ EmitLoadTypeFeedbackVector(a2);
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);

View File

@ -2944,7 +2944,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ EmitLoadTypeFeedbackVector(rbx); __ EmitLoadTypeFeedbackVector(rbx);
__ Move(rdx, SmiFromSlot(expr->CallNewFeedbackSlot())); __ Move(rdx, SmiFromSlot(expr->CallNewFeedbackSlot()));
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); CallConstructStub stub(isolate());
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
PrepareForBailoutForId(expr->ReturnId(), TOS_REG); PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
// Restore context register. // Restore context register.
@ -2972,20 +2972,15 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
// constructor invocation. // constructor invocation.
SetConstructCallPosition(expr, arg_count); SetConstructCallPosition(expr, arg_count);
// Load new target into rcx. // Load new target into rdx.
VisitForAccumulatorValue(super_call_ref->new_target_var()); VisitForAccumulatorValue(super_call_ref->new_target_var());
__ movp(rcx, result_register()); __ movp(rdx, result_register());
// Load function and argument count into rdi and rax. // Load function and argument count into rdi and rax.
__ Set(rax, arg_count); __ Set(rax, arg_count);
__ movp(rdi, Operand(rsp, arg_count * kPointerSize)); __ movp(rdi, Operand(rsp, arg_count * kPointerSize));
// Record call targets in unoptimized code. __ Call(isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
__ EmitLoadTypeFeedbackVector(rbx);
__ Move(rdx, SmiFromSlot(expr->CallFeedbackSlot()));
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);

View File

@ -599,19 +599,6 @@ enum InlineCacheState {
}; };
enum CallConstructorFlags {
NO_CALL_CONSTRUCTOR_FLAGS = 0,
// The call target is cached in the instruction stream.
RECORD_CONSTRUCTOR_TARGET = 1,
// TODO(bmeurer): Kill these SUPER_* modes and use the Construct builtin
// directly instead; also there's no point in collecting any "targets" for
// super constructor calls, since these are known when we optimize the
// constructor that contains the super call.
SUPER_CONSTRUCTOR_CALL = 1 << 1,
SUPER_CALL_RECORD_TARGET = SUPER_CONSTRUCTOR_CALL | RECORD_CONSTRUCTOR_TARGET
};
enum CacheHolderFlag { enum CacheHolderFlag {
kCacheOnPrototype, kCacheOnPrototype,
kCacheOnPrototypeReceiverIsDictionary, kCacheOnPrototypeReceiverIsDictionary,

View File

@ -1136,11 +1136,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector // Use undefined feedback vector
__ LoadRoot(ebx, Heap::kUndefinedValueRootIndex); __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
__ mov(edi, Operand(ebp, kFunctionOffset)); __ mov(edi, Operand(ebp, kFunctionOffset));
__ mov(ecx, Operand(ebp, kNewTargetOffset)); __ mov(edx, Operand(ebp, kNewTargetOffset));
// Call the function. // Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); __ Call(masm->isolate()->builtins()->Construct(),
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); RelocInfo::CONSTRUCT_CALL);
// Leave internal frame. // Leave internal frame.
} }
@ -1633,21 +1633,22 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- edi : the constructor to call (can be any Object) // -- edi : the constructor to call (can be any Object)
// ----------------------------------- // -----------------------------------
// Check if target has a [[Construct]] internal method. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(edi, &non_constructor, Label::kNear); __ JumpIfSmi(edi, &non_constructor, Label::kNear);
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
__ j(zero, &non_constructor, Label::kNear);
// Dispatch based on instance type. // Dispatch based on instance type.
__ CmpInstanceType(ecx, JS_FUNCTION_TYPE); __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(), __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructProxy(), __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
// Check if target has a [[Construct]] internal method.
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
__ j(zero, &non_constructor, Label::kNear);
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.

View File

@ -1903,16 +1903,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
} }
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
bool is_super) {
// eax : number of arguments to the construct function // eax : number of arguments to the construct function
// ebx : feedback vector // ebx : feedback vector
// edx : slot in feedback vector (Smi) // edx : slot in feedback vector (Smi)
// edi : the function to call // edi : the function to call
// esp[0]: original receiver (for IsSuperConstructorCall)
if (is_super) {
__ pop(ecx);
}
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
@ -1923,29 +1918,19 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
__ push(edi); __ push(edi);
__ push(edx); __ push(edx);
__ push(ebx); __ push(ebx);
if (is_super) {
__ push(ecx);
}
__ CallStub(stub); __ CallStub(stub);
if (is_super) {
__ pop(ecx);
}
__ pop(ebx); __ pop(ebx);
__ pop(edx); __ pop(edx);
__ pop(edi); __ pop(edi);
__ pop(eax); __ pop(eax);
__ SmiUntag(eax); __ SmiUntag(eax);
} }
if (is_super) {
__ push(ecx);
}
} }
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a feedback vector slot. Cache states // Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and // are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic. // megamorphic.
@ -1953,7 +1938,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// ebx : feedback vector // ebx : feedback vector
// edx : slot in feedback vector (Smi) // edx : slot in feedback vector (Smi)
// edi : the function to call // edi : the function to call
// esp[0]: original receiver (for IsSuperConstructorCall)
Isolate* isolate = masm->isolate(); Isolate* isolate = masm->isolate();
Label initialize, done, miss, megamorphic, not_array_function; Label initialize, done, miss, megamorphic, not_array_function;
@ -2019,12 +2003,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Create an AllocationSite if we don't already have it, store it in the // Create an AllocationSite if we don't already have it, store it in the
// slot. // slot.
CreateAllocationSiteStub create_stub(isolate); CreateAllocationSiteStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub, is_super); CallStubInRecordCallTarget(masm, &create_stub);
__ jmp(&done); __ jmp(&done);
__ bind(&not_array_function); __ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(isolate); CreateWeakCellStub weak_cell_stub(isolate);
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done); __ bind(&done);
} }
@ -2032,14 +2016,9 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
void CallConstructStub::Generate(MacroAssembler* masm) { void CallConstructStub::Generate(MacroAssembler* masm) {
// eax : number of arguments // eax : number of arguments
// ebx : feedback vector // ebx : feedback vector
// ecx : new target (for IsSuperConstructorCall)
// edx : slot in feedback vector (Smi, for RecordCallTarget) // edx : slot in feedback vector (Smi, for RecordCallTarget)
// edi : constructor function // edi : constructor function
if (IsSuperConstructorCall()) {
__ push(ecx);
}
Label non_function; Label non_function;
// Check that function is not a smi. // Check that function is not a smi.
__ JumpIfSmi(edi, &non_function); __ JumpIfSmi(edi, &non_function);
@ -2047,29 +2026,22 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(not_equal, &non_function); __ j(not_equal, &non_function);
if (RecordCallTarget()) { GenerateRecordCallTarget(masm);
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
Label feedback_register_initialized; Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into ebx, or undefined. // Put the AllocationSite from the feedback vector into ebx, or undefined.
__ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size, __ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize)); FixedArray::kHeaderSize));
Handle<Map> allocation_site_map = Handle<Map> allocation_site_map = isolate()->factory()->allocation_site_map();
isolate()->factory()->allocation_site_map(); __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
__ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map)); __ j(equal, &feedback_register_initialized);
__ j(equal, &feedback_register_initialized); __ mov(ebx, isolate()->factory()->undefined_value());
__ mov(ebx, isolate()->factory()->undefined_value()); __ bind(&feedback_register_initialized);
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(ebx); __ AssertUndefinedOrAllocationSite(ebx);
}
if (IsSuperConstructorCall()) { // Pass new target to construct stub.
__ pop(edx); __ mov(edx, edi);
} else {
// Pass new target to construct stub.
__ mov(edx, edi);
}
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).
@ -2079,7 +2051,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ jmp(ecx); __ jmp(ecx);
__ bind(&non_function); __ bind(&non_function);
if (IsSuperConstructorCall()) __ Drop(1);
__ mov(edx, edi); __ mov(edx, edi);
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); __ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
} }

View File

@ -210,6 +210,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
} }
void ConstructTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// eax : number of arguments
// edx : the new target
// edi : the target to call
Register registers[] = {edi, edx, eax};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific( void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
Register registers[] = {ecx, ebx, eax}; Register registers[] = {ecx, ebx, eax};

View File

@ -426,6 +426,19 @@ CallTrampolineDescriptor::BuildCallInterfaceDescriptorFunctionType(
} }
Type::FunctionType*
ConstructTrampolineDescriptor::BuildCallInterfaceDescriptorFunctionType(
Isolate* isolate, int paramater_count) {
Zone* zone = isolate->interface_descriptor_zone();
Type::FunctionType* function =
Type::FunctionType::New(AnyTagged(zone), Type::Undefined(), 3, zone);
function->InitParameter(0, AnyTagged(zone)); // target
function->InitParameter(1, AnyTagged(zone)); // new.target
function->InitParameter(2, UntaggedIntegral32(zone)); // actual #arguments
return function;
}
Type::FunctionType* Type::FunctionType*
CallFunctionWithFeedbackDescriptor::BuildCallInterfaceDescriptorFunctionType( CallFunctionWithFeedbackDescriptor::BuildCallInterfaceDescriptorFunctionType(
Isolate* isolate, int paramater_count) { Isolate* isolate, int paramater_count) {

View File

@ -39,6 +39,7 @@ class PlatformInterfaceDescriptor;
V(CallFunctionWithFeedbackAndVector) \ V(CallFunctionWithFeedbackAndVector) \
V(CallConstruct) \ V(CallConstruct) \
V(CallTrampoline) \ V(CallTrampoline) \
V(ConstructTrampoline) \
V(RegExpConstructResult) \ V(RegExpConstructResult) \
V(TransitionElementsKind) \ V(TransitionElementsKind) \
V(AllocateHeapNumber) \ V(AllocateHeapNumber) \
@ -458,6 +459,13 @@ class CallTrampolineDescriptor : public CallInterfaceDescriptor {
}; };
class ConstructTrampolineDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(ConstructTrampolineDescriptor,
CallInterfaceDescriptor)
};
class CallFunctionDescriptor : public CallInterfaceDescriptor { class CallFunctionDescriptor : public CallInterfaceDescriptor {
public: public:
DECLARE_DESCRIPTOR(CallFunctionDescriptor, CallInterfaceDescriptor) DECLARE_DESCRIPTOR(CallFunctionDescriptor, CallInterfaceDescriptor)

View File

@ -1398,11 +1398,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector // Use undefined feedback vector
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex); __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ lw(a1, MemOperand(fp, kFunctionOffset)); __ lw(a1, MemOperand(fp, kFunctionOffset));
__ lw(t0, MemOperand(fp, kNewTargetOffset)); __ lw(a3, MemOperand(fp, kNewTargetOffset));
// Call the function. // Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); __ Call(masm->isolate()->builtins()->Construct(),
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); RelocInfo::CONSTRUCT_CALL);
// Leave internal frame. // Leave internal frame.
} }
@ -1678,21 +1678,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// ----------------------------------- // -----------------------------------
// Check if target has a [[Construct]] internal method. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(a1, &non_constructor); __ JumpIfSmi(a1, &non_constructor);
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t2, t2, Operand(1 << Map::kIsCallable));
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
// Dispatch based on instance type. // Dispatch based on instance type.
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset)); __ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(masm->isolate()->builtins()->ConstructFunction(), __ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE)); RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
eq, t2, Operand(JS_FUNCTION_PROXY_TYPE)); eq, t2, Operand(JS_FUNCTION_PROXY_TYPE));
// Check if target has a [[Construct]] internal method.
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t2, t2, Operand(1 << Map::kIsCallable));
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.

View File

@ -2389,19 +2389,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
} }
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
bool is_super) {
// a0 : number of arguments to the construct function // a0 : number of arguments to the construct function
// a2 : feedback vector // a2 : feedback vector
// a3 : slot in feedback vector (Smi) // a3 : slot in feedback vector (Smi)
// a1 : the function to call // a1 : the function to call
// t0 : new target (for IsSuperConstructorCall)
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
const RegList kSavedRegs = 1 << 4 | // a0 const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1 1 << 5 | // a1
1 << 6 | // a2 1 << 6 | // a2
1 << 7 | // a3 1 << 7; // a3
BoolToInt(is_super) << 8; // t0
// Number-of-arguments register must be smi-tagged to call out. // Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(a0); __ SmiTag(a0);
@ -2414,7 +2411,7 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
} }
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a feedback vector slot. Cache states // Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and // are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic. // megamorphic.
@ -2422,7 +2419,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// a1 : the function to call // a1 : the function to call
// a2 : feedback vector // a2 : feedback vector
// a3 : slot in feedback vector (Smi) // a3 : slot in feedback vector (Smi)
// t0 : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function; Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
@ -2492,12 +2488,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Create an AllocationSite if we don't already have it, store it in the // Create an AllocationSite if we don't already have it, store it in the
// slot. // slot.
CreateAllocationSiteStub create_stub(masm->isolate()); CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, is_super); CallStubInRecordCallTarget(masm, &create_stub);
__ Branch(&done); __ Branch(&done);
__ bind(&not_array_function); __ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate()); CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done); __ bind(&done);
} }
@ -2507,7 +2503,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// a1 : the function to call // a1 : the function to call
// a2 : feedback vector // a2 : feedback vector
// a3 : slot in feedback vector (Smi, for RecordCallTarget) // a3 : slot in feedback vector (Smi, for RecordCallTarget)
// t0 : new target (for IsSuperConstructorCall)
Label non_function; Label non_function;
// Check that the function is not a smi. // Check that the function is not a smi.
@ -2516,29 +2511,23 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ GetObjectType(a1, t1, t1); __ GetObjectType(a1, t1, t1);
__ Branch(&non_function, ne, t1, Operand(JS_FUNCTION_TYPE)); __ Branch(&non_function, ne, t1, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) { GenerateRecordCallTarget(masm);
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ sll(at, a3, kPointerSizeLog2 - kSmiTagSize); __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t1, a2, at); __ Addu(t1, a2, at);
Label feedback_register_initialized; Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined. // Put the AllocationSite from the feedback vector into a2, or undefined.
__ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize)); __ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize));
__ lw(t1, FieldMemOperand(a2, AllocationSite::kMapOffset)); __ lw(t1, FieldMemOperand(a2, AllocationSite::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&feedback_register_initialized, eq, t1, Operand(at)); __ Branch(&feedback_register_initialized, eq, t1, Operand(at));
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex); __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized); __ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(a2, t1); __ AssertUndefinedOrAllocationSite(a2, t1);
}
// Pass function as new target. // Pass function as new target.
if (IsSuperConstructorCall()) { __ mov(a3, a1);
__ mov(a3, t0);
} else {
__ mov(a3, a1);
}
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).

View File

@ -204,6 +204,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
} }
void ConstructTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: target
// a3: new target
// a0: number of arguments
Register registers[] = {a1, a3, a0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific( void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
Register registers[] = {a2, a1, a0}; Register registers[] = {a2, a1, a0};

View File

@ -1395,11 +1395,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector // Use undefined feedback vector
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex); __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ ld(a1, MemOperand(fp, kFunctionOffset)); __ ld(a1, MemOperand(fp, kFunctionOffset));
__ ld(a4, MemOperand(fp, kNewTargetOffset)); __ ld(a3, MemOperand(fp, kNewTargetOffset));
// Call the function. // Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); __ Call(masm->isolate()->builtins()->Construct(),
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); RelocInfo::CONSTRUCT_CALL);
// Leave internal frame. // Leave internal frame.
} }
@ -1674,21 +1674,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// ----------------------------------- // -----------------------------------
// Check if target has a [[Construct]] internal method. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(a1, &non_constructor); __ JumpIfSmi(a1, &non_constructor);
__ ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t2, t2, Operand(1 << Map::kIsCallable));
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
// Dispatch based on instance type. // Dispatch based on instance type.
__ ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset)); __ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(masm->isolate()->builtins()->ConstructFunction(), __ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE)); RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
eq, t2, Operand(JS_FUNCTION_PROXY_TYPE)); eq, t2, Operand(JS_FUNCTION_PROXY_TYPE));
// Check if target has a [[Construct]] internal method.
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t2, t2, Operand(1 << Map::kIsCallable));
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.

View File

@ -2423,19 +2423,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
} }
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
bool is_super) {
// a0 : number of arguments to the construct function // a0 : number of arguments to the construct function
// a2 : feedback vector // a2 : feedback vector
// a3 : slot in feedback vector (Smi) // a3 : slot in feedback vector (Smi)
// a1 : the function to call // a1 : the function to call
// a4 : new target (for IsSuperConstructorCall)
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
const RegList kSavedRegs = 1 << 4 | // a0 const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1 1 << 5 | // a1
1 << 6 | // a2 1 << 6 | // a2
1 << 7 | // a3 1 << 7; // a3
BoolToInt(is_super) << 8; // a4
// Number-of-arguments register must be smi-tagged to call out. // Number-of-arguments register must be smi-tagged to call out.
@ -2449,7 +2446,7 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
} }
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a feedback vector slot. Cache states // Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and // are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic. // megamorphic.
@ -2457,7 +2454,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// a1 : the function to call // a1 : the function to call
// a2 : feedback vector // a2 : feedback vector
// a3 : slot in feedback vector (Smi) // a3 : slot in feedback vector (Smi)
// a4 : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function; Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
@ -2527,13 +2523,13 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// Create an AllocationSite if we don't already have it, store it in the // Create an AllocationSite if we don't already have it, store it in the
// slot. // slot.
CreateAllocationSiteStub create_stub(masm->isolate()); CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, is_super); CallStubInRecordCallTarget(masm, &create_stub);
__ Branch(&done); __ Branch(&done);
__ bind(&not_array_function); __ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate()); CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done); __ bind(&done);
} }
@ -2543,7 +2539,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// a1 : the function to call // a1 : the function to call
// a2 : feedback vector // a2 : feedback vector
// a3 : slot in feedback vector (Smi, for RecordCallTarget) // a3 : slot in feedback vector (Smi, for RecordCallTarget)
// a4 : new target (for IsSuperConstructorCall)
Label non_function; Label non_function;
// Check that the function is not a smi. // Check that the function is not a smi.
@ -2552,29 +2547,23 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ GetObjectType(a1, a5, a5); __ GetObjectType(a1, a5, a5);
__ Branch(&non_function, ne, a5, Operand(JS_FUNCTION_TYPE)); __ Branch(&non_function, ne, a5, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) { GenerateRecordCallTarget(masm);
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ dsrl(at, a3, 32 - kPointerSizeLog2); __ dsrl(at, a3, 32 - kPointerSizeLog2);
__ Daddu(a5, a2, at); __ Daddu(a5, a2, at);
Label feedback_register_initialized; Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined. // Put the AllocationSite from the feedback vector into a2, or undefined.
__ ld(a2, FieldMemOperand(a5, FixedArray::kHeaderSize)); __ ld(a2, FieldMemOperand(a5, FixedArray::kHeaderSize));
__ ld(a5, FieldMemOperand(a2, AllocationSite::kMapOffset)); __ ld(a5, FieldMemOperand(a2, AllocationSite::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&feedback_register_initialized, eq, a5, Operand(at)); __ Branch(&feedback_register_initialized, eq, a5, Operand(at));
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex); __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized); __ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(a2, a5); __ AssertUndefinedOrAllocationSite(a2, a5);
}
// Pass function as new target. // Pass function as new target.
if (IsSuperConstructorCall()) { __ mov(a3, a1);
__ mov(a3, a4);
} else {
__ mov(a3, a1);
}
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).

View File

@ -204,6 +204,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
} }
void ConstructTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: target
// a3: new target
// a0: number of arguments
Register registers[] = {a1, a3, a0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific( void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
Register registers[] = {a2, a1, a0}; Register registers[] = {a2, a1, a0};

View File

@ -5186,21 +5186,6 @@ bool Code::back_edges_patched_for_osr() {
uint16_t Code::to_boolean_state() { return extra_ic_state(); } uint16_t Code::to_boolean_state() { return extra_ic_state(); }
bool Code::has_function_cache() {
DCHECK(kind() == STUB);
return HasFunctionCacheField::decode(
READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
}
void Code::set_has_function_cache(bool flag) {
DCHECK(kind() == STUB);
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
int updated = HasFunctionCacheField::update(previous, flag);
WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
}
bool Code::marked_for_deoptimization() { bool Code::marked_for_deoptimization() {
DCHECK(kind() == OPTIMIZED_FUNCTION); DCHECK(kind() == OPTIMIZED_FUNCTION);
return MarkedForDeoptimizationField::decode( return MarkedForDeoptimizationField::decode(

View File

@ -5018,12 +5018,6 @@ class Code: public HeapObject {
// [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in. // [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in.
inline uint16_t to_boolean_state(); inline uint16_t to_boolean_state();
// [has_function_cache]: For kind STUB tells whether there is a function
// cache is passed to the stub.
inline bool has_function_cache();
inline void set_has_function_cache(bool flag);
// [marked_for_deoptimization]: For kind OPTIMIZED_FUNCTION tells whether // [marked_for_deoptimization]: For kind OPTIMIZED_FUNCTION tells whether
// the code is going to be deoptimized because of dead embedded maps. // the code is going to be deoptimized because of dead embedded maps.
inline bool marked_for_deoptimization(); inline bool marked_for_deoptimization();
@ -5269,9 +5263,8 @@ class Code: public HeapObject {
// KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION) // KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION)
static const int kStackSlotsFirstBit = 0; static const int kStackSlotsFirstBit = 0;
static const int kStackSlotsBitCount = 24; static const int kStackSlotsBitCount = 24;
static const int kHasFunctionCacheBit = static const int kMarkedForDeoptimizationBit =
kStackSlotsFirstBit + kStackSlotsBitCount; kStackSlotsFirstBit + kStackSlotsBitCount;
static const int kMarkedForDeoptimizationBit = kHasFunctionCacheBit + 1;
static const int kIsTurbofannedBit = kMarkedForDeoptimizationBit + 1; static const int kIsTurbofannedBit = kMarkedForDeoptimizationBit + 1;
static const int kCanHaveWeakObjects = kIsTurbofannedBit + 1; static const int kCanHaveWeakObjects = kIsTurbofannedBit + 1;
@ -5280,10 +5273,8 @@ class Code: public HeapObject {
class StackSlotsField: public BitField<int, class StackSlotsField: public BitField<int,
kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT
class HasFunctionCacheField : public BitField<bool, kHasFunctionCacheBit, 1> {
}; // NOLINT
class MarkedForDeoptimizationField class MarkedForDeoptimizationField
: public BitField<bool, kMarkedForDeoptimizationBit, 1> {}; // NOLINT : public BitField<bool, kMarkedForDeoptimizationBit, 1> {}; // NOLINT
class IsTurbofannedField : public BitField<bool, kIsTurbofannedBit, 1> { class IsTurbofannedField : public BitField<bool, kIsTurbofannedBit, 1> {
}; // NOLINT }; // NOLINT
class CanHaveWeakObjectsField class CanHaveWeakObjectsField

View File

@ -1175,11 +1175,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector // Use undefined feedback vector
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
__ movp(rdi, Operand(rbp, kFunctionOffset)); __ movp(rdi, Operand(rbp, kFunctionOffset));
__ movp(rcx, Operand(rbp, kNewTargetOffset)); __ movp(rdx, Operand(rbp, kNewTargetOffset));
// Call the function. // Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); __ Call(masm->isolate()->builtins()->Construct(),
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); RelocInfo::CONSTRUCT_CALL);
// Leave internal frame. // Leave internal frame.
} }
@ -1820,22 +1820,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
StackArgumentsAccessor args(rsp, rax); StackArgumentsAccessor args(rsp, rax);
// Check if target has a [[Construct]] internal method. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(rdi, &non_constructor, Label::kNear); __ JumpIfSmi(rdi, &non_constructor, Label::kNear);
__ movp(rcx, FieldOperand(rdi, HeapObject::kMapOffset));
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &non_constructor, Label::kNear);
// Dispatch based on instance type. // Dispatch based on instance type.
__ CmpInstanceType(rcx, JS_FUNCTION_TYPE); __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(), __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructProxy(), __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
// Check if target has a [[Construct]] internal method.
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &non_constructor, Label::kNear);
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.

View File

@ -1753,11 +1753,9 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
} }
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
bool is_super) {
// rax : number of arguments to the construct function // rax : number of arguments to the construct function
// rbx : feedback vector // rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi) // rdx : slot in feedback vector (Smi)
// rdi : the function to call // rdi : the function to call
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
@ -1769,15 +1767,9 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
__ Integer32ToSmi(rdx, rdx); __ Integer32ToSmi(rdx, rdx);
__ Push(rdx); __ Push(rdx);
__ Push(rbx); __ Push(rbx);
if (is_super) {
__ Push(rcx);
}
__ CallStub(stub); __ CallStub(stub);
if (is_super) {
__ Pop(rcx);
}
__ Pop(rbx); __ Pop(rbx);
__ Pop(rdx); __ Pop(rdx);
__ Pop(rdi); __ Pop(rdi);
@ -1786,13 +1778,12 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
} }
static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a feedback vector slot. Cache states // Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and // are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic. // megamorphic.
// rax : number of arguments to the construct function // rax : number of arguments to the construct function
// rbx : feedback vector // rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi) // rdx : slot in feedback vector (Smi)
// rdi : the function to call // rdi : the function to call
Isolate* isolate = masm->isolate(); Isolate* isolate = masm->isolate();
@ -1860,12 +1851,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
__ j(not_equal, &not_array_function); __ j(not_equal, &not_array_function);
CreateAllocationSiteStub create_stub(isolate); CreateAllocationSiteStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub, is_super); CallStubInRecordCallTarget(masm, &create_stub);
__ jmp(&done_no_smi_convert); __ jmp(&done_no_smi_convert);
__ bind(&not_array_function); __ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(isolate); CreateWeakCellStub weak_cell_stub(isolate);
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ jmp(&done_no_smi_convert); __ jmp(&done_no_smi_convert);
__ bind(&done); __ bind(&done);
@ -1878,8 +1869,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
void CallConstructStub::Generate(MacroAssembler* masm) { void CallConstructStub::Generate(MacroAssembler* masm) {
// rax : number of arguments // rax : number of arguments
// rbx : feedback vector // rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall) // rdx : slot in feedback vector (Smi)
// rdx : slot in feedback vector (Smi, for RecordCallTarget)
// rdi : constructor function // rdi : constructor function
Label non_function; Label non_function;
@ -1889,28 +1879,22 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, r11); __ CmpObjectType(rdi, JS_FUNCTION_TYPE, r11);
__ j(not_equal, &non_function); __ j(not_equal, &non_function);
if (RecordCallTarget()) { GenerateRecordCallTarget(masm);
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
__ SmiToInteger32(rdx, rdx); __ SmiToInteger32(rdx, rdx);
Label feedback_register_initialized; Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into rbx, or undefined. // Put the AllocationSite from the feedback vector into rbx, or undefined.
__ movp(rbx, FieldOperand(rbx, rdx, times_pointer_size, __ movp(rbx,
FixedArray::kHeaderSize)); FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
__ CompareRoot(FieldOperand(rbx, 0), Heap::kAllocationSiteMapRootIndex); __ CompareRoot(FieldOperand(rbx, 0), Heap::kAllocationSiteMapRootIndex);
__ j(equal, &feedback_register_initialized); __ j(equal, &feedback_register_initialized, Label::kNear);
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized); __ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(rbx); __ AssertUndefinedOrAllocationSite(rbx);
}
// Pass new target to construct stub. // Pass new target to construct stub.
if (IsSuperConstructorCall()) { __ movp(rdx, rdi);
__ movp(rdx, rcx);
} else {
__ movp(rdx, rdi);
}
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).

View File

@ -186,12 +186,11 @@ void CallConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
// rax : number of arguments // rax : number of arguments
// rbx : feedback vector // rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi, for RecordCallTarget) // rdx : slot in feedback vector (Smi, for RecordCallTarget)
// rdi : constructor function // rdi : constructor function
// TODO(turbofan): So far we don't gather type feedback and hence skip the // TODO(turbofan): So far we don't gather type feedback and hence skip the
// slot parameter, but ArrayConstructStub needs the vector to be undefined. // slot parameter, but ArrayConstructStub needs the vector to be undefined.
Register registers[] = {rax, rdi, rcx, rbx}; Register registers[] = {rax, rdi, rbx};
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
@ -205,6 +204,16 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
} }
void ConstructTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// rax : number of arguments
// rdx : the new target
// rdi : the target to call
Register registers[] = {rdi, rdx, rax};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific( void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
Register registers[] = {rcx, rbx, rax}; Register registers[] = {rcx, rbx, rax};