[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
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ ldr(r1, MemOperand(fp, kFunctionOffset));
__ ldr(r4, MemOperand(fp, kNewTargetOffset));
__ ldr(r3, MemOperand(fp, kNewTargetOffset));
// Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
__ Call(masm->isolate()->builtins()->Construct(),
RelocInfo::CONSTRUCT_CALL);
// Leave internal frame.
}
@ -1655,22 +1655,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// 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;
__ 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.
__ CompareInstanceType(r4, r5, JS_FUNCTION_TYPE);
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
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.
{
// 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,
bool is_super) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
// r0 : number of arguments to the construct function
// r1 : the function to call
// r2 : feedback vector
// r3 : slot in feedback vector (Smi)
// r4 : new target (for IsSuperConstructorCall)
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(r0);
__ Push(r3, r2, r1, r0);
if (is_super) {
__ Push(r4);
}
__ CallStub(stub);
if (is_super) {
__ Pop(r4);
}
__ Pop(r3, r2, r1, 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
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
@ -2297,7 +2289,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// r1 : the function to call
// r2 : feedback vector
// r3 : slot in feedback vector (Smi)
// r4 : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function;
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
// slot.
CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, is_super);
CallStubInRecordCallTarget(masm, &create_stub);
__ b(&done);
__ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super);
CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done);
}
@ -2384,7 +2375,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// r1 : the function to call
// r2 : feedback vector
// r3 : slot in feedback vector (Smi, for RecordCallTarget)
// r4 : new target (for IsSuperConstructorCall)
Label non_function;
// Check that the function is not a smi.
@ -2393,28 +2383,22 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ CompareObjectType(r1, r5, r5, JS_FUNCTION_TYPE);
__ b(ne, &non_function);
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
GenerateRecordCallTarget(masm);
__ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3));
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into r2, or undefined.
__ ldr(r2, FieldMemOperand(r5, FixedArray::kHeaderSize));
__ ldr(r5, FieldMemOperand(r2, AllocationSite::kMapOffset));
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
__ b(eq, &feedback_register_initialized);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3));
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into r2, or undefined.
__ ldr(r2, FieldMemOperand(r5, FixedArray::kHeaderSize));
__ ldr(r5, FieldMemOperand(r2, AllocationSite::kMapOffset));
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
__ b(eq, &feedback_register_initialized);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(r2, r5);
}
__ AssertUndefinedOrAllocationSite(r2, r5);
// Pass function as new target.
if (IsSuperConstructorCall()) {
__ mov(r3, r4);
} else {
__ mov(r3, r1);
}
__ mov(r3, r1);
// Tail call to the function-specific construct stub (still in the caller
// 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(
CallInterfaceDescriptorData* data) {
Register registers[] = {r2, r1, r0};

View File

@ -1372,11 +1372,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector
__ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
__ Ldr(x1, MemOperand(fp, kFunctionOffset));
__ Ldr(x4, MemOperand(fp, kNewTargetOffset));
__ Ldr(x3, MemOperand(fp, kNewTargetOffset));
// Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
__ Call(masm->isolate()->builtins()->Construct(),
RelocInfo::CONSTRUCT_CALL);
// Leave internal frame.
}
@ -1648,21 +1648,22 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// 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;
__ 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.
__ CompareInstanceType(x4, x5, JS_FUNCTION_TYPE);
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
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.
{
// 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,
Register argc, Register function,
Register feedback_vector, Register index,
Register new_target, bool is_super) {
Register new_target) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Number-of-arguments register must be smi-tagged to call out.
__ SmiTag(argc);
if (is_super) {
__ Push(argc, function, feedback_vector, index, new_target);
} else {
__ Push(argc, function, feedback_vector, index);
}
__ Push(argc, function, feedback_vector, index);
DCHECK(feedback_vector.Is(x2) && index.Is(x3));
__ CallStub(stub);
if (is_super) {
__ Pop(new_target, index, feedback_vector, function, argc);
} else {
__ Pop(index, feedback_vector, function, argc);
}
__ Pop(index, feedback_vector, function, argc);
__ SmiUntag(argc);
}
@ -2649,8 +2641,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, Register argc,
Register function,
Register feedback_vector, Register index,
Register new_target, Register scratch1,
Register scratch2, Register scratch3,
bool is_super) {
Register scratch2, Register scratch3) {
ASM_LOCATION("GenerateRecordCallTarget");
DCHECK(!AreAliased(scratch1, scratch2, scratch3, argc, function,
feedback_vector, index, new_target));
@ -2660,7 +2651,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, Register argc,
// function : the function to call
// feedback_vector : the feedback vector
// index : slot in feedback vector (smi)
// new_target : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function;
DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
@ -2736,13 +2726,13 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, Register argc,
// slot.
CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, argc, function,
feedback_vector, index, new_target, is_super);
feedback_vector, index, new_target);
__ B(&done);
__ Bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, argc, function,
feedback_vector, index, new_target, is_super);
feedback_vector, index, new_target);
__ Bind(&done);
}
@ -2753,7 +2743,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// x1 : the function to call
// x2 : feedback vector
// x3 : slot in feedback vector (Smi, for RecordCallTarget)
// x4 : new target (for IsSuperConstructorCall)
Register function = x1;
Label non_function;
@ -2764,28 +2753,21 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE,
&non_function);
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm, x0, function, x2, x3, x4, x5, x11, x12,
IsSuperConstructorCall());
GenerateRecordCallTarget(masm, x0, function, x2, x3, x4, x5, x11, x12);
__ Add(x5, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into x2, or undefined.
__ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize));
__ Ldr(x5, FieldMemOperand(x2, AllocationSite::kMapOffset));
__ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex,
&feedback_register_initialized);
__ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ Add(x5, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into x2, or undefined.
__ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize));
__ Ldr(x5, FieldMemOperand(x2, AllocationSite::kMapOffset));
__ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex,
&feedback_register_initialized);
__ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(x2, x5);
}
__ AssertUndefinedOrAllocationSite(x2, x5);
if (IsSuperConstructorCall()) {
__ Mov(x3, x4);
} else {
__ Mov(x3, function);
}
__ Mov(x3, function);
// Tail call to the function-specific construct stub (still in the caller
// 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(
CallInterfaceDescriptorData* data) {
// 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
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsAndCall(),

View File

@ -103,6 +103,7 @@ class CodeFactory final {
ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable CallFunction(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable Construct(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(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
os << "ArrayConstructorStub";
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:
CallConstructStub(Isolate* isolate, CallConstructorFlags flags)
: 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> {};
explicit CallConstructStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(CallConstruct);
DEFINE_PLATFORM_CODE_STUB(CallConstruct, PlatformCodeStub);

View File

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

View File

@ -33,7 +33,6 @@ class LCodeGen;
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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> {
public:
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) {
DCHECK(ToRegister(instr->context()).is(cp));
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) {
stream->Add("= ");
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) {
LOperand* context = UseFixed(instr->context(), cp);
// The call to ArrayConstructCode will expect the constructor to be in x1.

View File

@ -35,7 +35,6 @@ class LCodeGen;
V(Branch) \
V(CallFunction) \
V(CallJSFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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> {
public:
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) {
DCHECK(instr->IsMarkedAsCall());
DCHECK(ToRegister(instr->context()).is(cp));

View File

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

View File

@ -62,7 +62,6 @@ class LChunkBuilder;
V(CallWithDescriptor) \
V(CallJSFunction) \
V(CallFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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 {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,

View File

@ -9993,18 +9993,21 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
instr = prev_instr;
} while (instr != check);
environment()->SetExpressionStackAt(receiver_index, function);
HInstruction* call =
PreProcessCall(New<HCallNew>(function, argument_count));
return ast_context()->ReturnInstruction(call, expr->id());
} else {
// The constructor function is both an operand to the instruction and an
// argument to the construct call.
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) {
DCHECK(ToRegister(instr->context()).is(esi));
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) {
stream->Add("= ");
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) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* constructor = UseFixed(instr->constructor(), edi);

View File

@ -37,7 +37,6 @@ class LCodeGen;
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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> {
public:
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) {
DCHECK(ToRegister(instr->context()).is(cp));
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) {
stream->Add("= ");
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) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), a1);

View File

@ -33,7 +33,6 @@ class LCodeGen;
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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> {
public:
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) {
DCHECK(ToRegister(instr->context()).is(cp));
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) {
stream->Add("= ");
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) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), a1);

View File

@ -35,7 +35,6 @@ class LCodeGen;
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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> {
public:
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) {
DCHECK(ToRegister(instr->context()).is(rsi));
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) {
stream->Add("= ");
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) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* constructor = UseFixed(instr->constructor(), rdi);

View File

@ -33,7 +33,6 @@ class LCodeGen;
V(CallJSFunction) \
V(CallWithDescriptor) \
V(CallFunction) \
V(CallNew) \
V(CallNewArray) \
V(CallRuntime) \
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> {
public:
LCallNewArray(LOperand* context, LOperand* constructor) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1136,11 +1136,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector
__ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
__ mov(edi, Operand(ebp, kFunctionOffset));
__ mov(ecx, Operand(ebp, kNewTargetOffset));
__ mov(edx, Operand(ebp, kNewTargetOffset));
// Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
__ Call(masm->isolate()->builtins()->Construct(),
RelocInfo::CONSTRUCT_CALL);
// Leave internal frame.
}
@ -1633,21 +1633,22 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- 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;
__ 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.
__ CmpInstanceType(ecx, JS_FUNCTION_TYPE);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
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.
{
// 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,
bool is_super) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
// eax : number of arguments to the construct function
// ebx : feedback vector
// edx : slot in feedback vector (Smi)
// edi : the function to call
// esp[0]: original receiver (for IsSuperConstructorCall)
if (is_super) {
__ pop(ecx);
}
{
FrameScope scope(masm, StackFrame::INTERNAL);
@ -1923,29 +1918,19 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
__ push(edi);
__ push(edx);
__ push(ebx);
if (is_super) {
__ push(ecx);
}
__ CallStub(stub);
if (is_super) {
__ pop(ecx);
}
__ pop(ebx);
__ pop(edx);
__ pop(edi);
__ pop(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
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
@ -1953,7 +1938,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// ebx : feedback vector
// edx : slot in feedback vector (Smi)
// edi : the function to call
// esp[0]: original receiver (for IsSuperConstructorCall)
Isolate* isolate = masm->isolate();
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
// slot.
CreateAllocationSiteStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
CallStubInRecordCallTarget(masm, &create_stub);
__ jmp(&done);
__ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(isolate);
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super);
CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done);
}
@ -2032,14 +2016,9 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
void CallConstructStub::Generate(MacroAssembler* masm) {
// eax : number of arguments
// ebx : feedback vector
// ecx : new target (for IsSuperConstructorCall)
// edx : slot in feedback vector (Smi, for RecordCallTarget)
// edi : constructor function
if (IsSuperConstructorCall()) {
__ push(ecx);
}
Label non_function;
// Check that function is not a smi.
__ JumpIfSmi(edi, &non_function);
@ -2047,29 +2026,22 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(not_equal, &non_function);
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
GenerateRecordCallTarget(masm);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into ebx, or undefined.
__ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize));
Handle<Map> allocation_site_map =
isolate()->factory()->allocation_site_map();
__ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
__ j(equal, &feedback_register_initialized);
__ mov(ebx, isolate()->factory()->undefined_value());
__ bind(&feedback_register_initialized);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into ebx, or undefined.
__ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize));
Handle<Map> allocation_site_map = isolate()->factory()->allocation_site_map();
__ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
__ j(equal, &feedback_register_initialized);
__ mov(ebx, isolate()->factory()->undefined_value());
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(ebx);
}
__ AssertUndefinedOrAllocationSite(ebx);
if (IsSuperConstructorCall()) {
__ pop(edx);
} else {
// Pass new target to construct stub.
__ mov(edx, edi);
}
// Pass new target to construct stub.
__ mov(edx, edi);
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
@ -2079,7 +2051,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ jmp(ecx);
__ bind(&non_function);
if (IsSuperConstructorCall()) __ Drop(1);
__ mov(edx, edi);
__ 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(
CallInterfaceDescriptorData* data) {
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*
CallFunctionWithFeedbackDescriptor::BuildCallInterfaceDescriptorFunctionType(
Isolate* isolate, int paramater_count) {

View File

@ -39,6 +39,7 @@ class PlatformInterfaceDescriptor;
V(CallFunctionWithFeedbackAndVector) \
V(CallConstruct) \
V(CallTrampoline) \
V(ConstructTrampoline) \
V(RegExpConstructResult) \
V(TransitionElementsKind) \
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 {
public:
DECLARE_DESCRIPTOR(CallFunctionDescriptor, CallInterfaceDescriptor)

View File

@ -1398,11 +1398,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ lw(a1, MemOperand(fp, kFunctionOffset));
__ lw(t0, MemOperand(fp, kNewTargetOffset));
__ lw(a3, MemOperand(fp, kNewTargetOffset));
// Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
__ Call(masm->isolate()->builtins()->Construct(),
RelocInfo::CONSTRUCT_CALL);
// Leave internal frame.
}
@ -1678,21 +1678,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// 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;
__ 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.
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
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.
{
// 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,
bool is_super) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
// a0 : number of arguments to the construct function
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// a1 : the function to call
// t0 : new target (for IsSuperConstructorCall)
FrameScope scope(masm, StackFrame::INTERNAL);
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7 | // a3
BoolToInt(is_super) << 8; // t0
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7; // a3
// Number-of-arguments register must be smi-tagged to call out.
__ 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
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
@ -2422,7 +2419,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// a1 : the function to call
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// t0 : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function;
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
// slot.
CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, is_super);
CallStubInRecordCallTarget(masm, &create_stub);
__ Branch(&done);
__ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super);
CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done);
}
@ -2507,7 +2503,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// a1 : the function to call
// a2 : feedback vector
// a3 : slot in feedback vector (Smi, for RecordCallTarget)
// t0 : new target (for IsSuperConstructorCall)
Label non_function;
// Check that the function is not a smi.
@ -2516,29 +2511,23 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ GetObjectType(a1, t1, t1);
__ Branch(&non_function, ne, t1, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
GenerateRecordCallTarget(masm);
__ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t1, a2, at);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined.
__ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize));
__ lw(t1, FieldMemOperand(a2, AllocationSite::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&feedback_register_initialized, eq, t1, Operand(at));
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t1, a2, at);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined.
__ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize));
__ lw(t1, FieldMemOperand(a2, AllocationSite::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&feedback_register_initialized, eq, t1, Operand(at));
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(a2, t1);
}
__ AssertUndefinedOrAllocationSite(a2, t1);
// Pass function as new target.
if (IsSuperConstructorCall()) {
__ mov(a3, t0);
} else {
__ mov(a3, a1);
}
__ mov(a3, a1);
// Tail call to the function-specific construct stub (still in the caller
// 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(
CallInterfaceDescriptorData* data) {
Register registers[] = {a2, a1, a0};

View File

@ -1395,11 +1395,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ ld(a1, MemOperand(fp, kFunctionOffset));
__ ld(a4, MemOperand(fp, kNewTargetOffset));
__ ld(a3, MemOperand(fp, kNewTargetOffset));
// Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
__ Call(masm->isolate()->builtins()->Construct(),
RelocInfo::CONSTRUCT_CALL);
// Leave internal frame.
}
@ -1674,21 +1674,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// 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;
__ 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.
__ ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
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.
{
// 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,
bool is_super) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
// a0 : number of arguments to the construct function
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// a1 : the function to call
// a4 : new target (for IsSuperConstructorCall)
FrameScope scope(masm, StackFrame::INTERNAL);
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7 | // a3
BoolToInt(is_super) << 8; // a4
const RegList kSavedRegs = 1 << 4 | // a0
1 << 5 | // a1
1 << 6 | // a2
1 << 7; // a3
// 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
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
@ -2457,7 +2454,6 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
// a1 : the function to call
// a2 : feedback vector
// a3 : slot in feedback vector (Smi)
// a4 : new target (for IsSuperConstructorCall)
Label initialize, done, miss, megamorphic, not_array_function;
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
// slot.
CreateAllocationSiteStub create_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &create_stub, is_super);
CallStubInRecordCallTarget(masm, &create_stub);
__ Branch(&done);
__ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(masm->isolate());
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super);
CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ bind(&done);
}
@ -2543,7 +2539,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
// a1 : the function to call
// a2 : feedback vector
// a3 : slot in feedback vector (Smi, for RecordCallTarget)
// a4 : new target (for IsSuperConstructorCall)
Label non_function;
// Check that the function is not a smi.
@ -2552,29 +2547,23 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ GetObjectType(a1, a5, a5);
__ Branch(&non_function, ne, a5, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
GenerateRecordCallTarget(masm);
__ dsrl(at, a3, 32 - kPointerSizeLog2);
__ Daddu(a5, a2, at);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined.
__ ld(a2, FieldMemOperand(a5, FixedArray::kHeaderSize));
__ ld(a5, FieldMemOperand(a2, AllocationSite::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&feedback_register_initialized, eq, a5, Operand(at));
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ dsrl(at, a3, 32 - kPointerSizeLog2);
__ Daddu(a5, a2, at);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined.
__ ld(a2, FieldMemOperand(a5, FixedArray::kHeaderSize));
__ ld(a5, FieldMemOperand(a2, AllocationSite::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&feedback_register_initialized, eq, a5, Operand(at));
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(a2, a5);
}
__ AssertUndefinedOrAllocationSite(a2, a5);
// Pass function as new target.
if (IsSuperConstructorCall()) {
__ mov(a3, a4);
} else {
__ mov(a3, a1);
}
__ mov(a3, a1);
// Tail call to the function-specific construct stub (still in the caller
// 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(
CallInterfaceDescriptorData* data) {
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(); }
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() {
DCHECK(kind() == OPTIMIZED_FUNCTION);
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.
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
// the code is going to be deoptimized because of dead embedded maps.
inline bool marked_for_deoptimization();
@ -5269,9 +5263,8 @@ class Code: public HeapObject {
// KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION)
static const int kStackSlotsFirstBit = 0;
static const int kStackSlotsBitCount = 24;
static const int kHasFunctionCacheBit =
static const int kMarkedForDeoptimizationBit =
kStackSlotsFirstBit + kStackSlotsBitCount;
static const int kMarkedForDeoptimizationBit = kHasFunctionCacheBit + 1;
static const int kIsTurbofannedBit = kMarkedForDeoptimizationBit + 1;
static const int kCanHaveWeakObjects = kIsTurbofannedBit + 1;
@ -5280,10 +5273,8 @@ class Code: public HeapObject {
class StackSlotsField: public BitField<int,
kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT
class HasFunctionCacheField : public BitField<bool, kHasFunctionCacheBit, 1> {
}; // NOLINT
class MarkedForDeoptimizationField
: public BitField<bool, kMarkedForDeoptimizationBit, 1> {}; // NOLINT
: public BitField<bool, kMarkedForDeoptimizationBit, 1> {}; // NOLINT
class IsTurbofannedField : public BitField<bool, kIsTurbofannedBit, 1> {
}; // NOLINT
class CanHaveWeakObjectsField

View File

@ -1175,11 +1175,11 @@ static void Generate_ConstructHelper(MacroAssembler* masm) {
// Use undefined feedback vector
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
__ movp(rdi, Operand(rbp, kFunctionOffset));
__ movp(rcx, Operand(rbp, kNewTargetOffset));
__ movp(rdx, Operand(rbp, kNewTargetOffset));
// Call the function.
CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
__ Call(masm->isolate()->builtins()->Construct(),
RelocInfo::CONSTRUCT_CALL);
// Leave internal frame.
}
@ -1820,22 +1820,23 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
// Check if target has a [[Construct]] internal method.
// Check if target is a Smi.
Label non_constructor;
__ 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.
__ CmpInstanceType(rcx, JS_FUNCTION_TYPE);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
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.
{
// 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,
bool is_super) {
static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
// rax : number of arguments to the construct function
// rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi)
// rdi : the function to call
FrameScope scope(masm, StackFrame::INTERNAL);
@ -1769,15 +1767,9 @@ static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub,
__ Integer32ToSmi(rdx, rdx);
__ Push(rdx);
__ Push(rbx);
if (is_super) {
__ Push(rcx);
}
__ CallStub(stub);
if (is_super) {
__ Pop(rcx);
}
__ Pop(rbx);
__ Pop(rdx);
__ 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
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// rax : number of arguments to the construct function
// rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi)
// rdi : the function to call
Isolate* isolate = masm->isolate();
@ -1860,12 +1851,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
__ j(not_equal, &not_array_function);
CreateAllocationSiteStub create_stub(isolate);
CallStubInRecordCallTarget(masm, &create_stub, is_super);
CallStubInRecordCallTarget(masm, &create_stub);
__ jmp(&done_no_smi_convert);
__ bind(&not_array_function);
CreateWeakCellStub weak_cell_stub(isolate);
CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super);
CallStubInRecordCallTarget(masm, &weak_cell_stub);
__ jmp(&done_no_smi_convert);
__ bind(&done);
@ -1878,8 +1869,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
void CallConstructStub::Generate(MacroAssembler* masm) {
// rax : number of arguments
// rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi, for RecordCallTarget)
// rdx : slot in feedback vector (Smi)
// rdi : constructor function
Label non_function;
@ -1889,28 +1879,22 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, r11);
__ j(not_equal, &non_function);
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm, IsSuperConstructorCall());
GenerateRecordCallTarget(masm);
__ SmiToInteger32(rdx, rdx);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into rbx, or undefined.
__ movp(rbx, FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize));
__ CompareRoot(FieldOperand(rbx, 0), Heap::kAllocationSiteMapRootIndex);
__ j(equal, &feedback_register_initialized);
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ SmiToInteger32(rdx, rdx);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into rbx, or undefined.
__ movp(rbx,
FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize));
__ CompareRoot(FieldOperand(rbx, 0), Heap::kAllocationSiteMapRootIndex);
__ j(equal, &feedback_register_initialized, Label::kNear);
__ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
__ bind(&feedback_register_initialized);
__ AssertUndefinedOrAllocationSite(rbx);
}
__ AssertUndefinedOrAllocationSite(rbx);
// Pass new target to construct stub.
if (IsSuperConstructorCall()) {
__ movp(rdx, rcx);
} else {
__ movp(rdx, rdi);
}
__ movp(rdx, rdi);
// Tail call to the function-specific construct stub (still in the caller
// context at this point).

View File

@ -186,12 +186,11 @@ void CallConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// rax : number of arguments
// rbx : feedback vector
// rcx : new target (for IsSuperConstructorCall)
// rdx : slot in feedback vector (Smi, for RecordCallTarget)
// rdi : constructor function
// TODO(turbofan): So far we don't gather type feedback and hence skip the
// 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);
}
@ -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(
CallInterfaceDescriptorData* data) {
Register registers[] = {rcx, rbx, rax};