[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:
parent
c1e7c8d972
commit
374b6ea210
@ -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.
|
||||
|
@ -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(¬_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).
|
||||
|
@ -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};
|
||||
|
@ -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.
|
||||
|
@ -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(¬_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).
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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(¬_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);
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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(¬_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).
|
||||
|
@ -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};
|
||||
|
@ -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.
|
||||
|
@ -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(¬_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).
|
||||
|
@ -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};
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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, ¬_array_function);
|
||||
|
||||
CreateAllocationSiteStub create_stub(isolate);
|
||||
CallStubInRecordCallTarget(masm, &create_stub, is_super);
|
||||
CallStubInRecordCallTarget(masm, &create_stub);
|
||||
__ jmp(&done_no_smi_convert);
|
||||
|
||||
__ bind(¬_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).
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user