Commit 4620a235 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [builtins] Sanitize the machinery around Construct calls.

  port 374b6ea2 (r32172)

  original commit message:
  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.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#32197}
parent e3c1cd84
......@@ -4134,19 +4134,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));
......
......@@ -330,15 +330,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);
......@@ -1262,14 +1253,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) \
......@@ -1914,25 +1913,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) {
......
......@@ -2946,7 +2946,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.
......@@ -2974,20 +2974,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);
......
......@@ -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.
......
......@@ -1610,16 +1610,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);
......@@ -1630,29 +1625,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.
......@@ -1660,7 +1645,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;
......@@ -1726,12 +1710,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);
}
......@@ -1739,14 +1723,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);
......@@ -1754,29 +1733,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).
......@@ -1786,7 +1758,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};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment