Revert of new classes: implement new.target passing to superclass constructor. (patchset #9 id:150001 of https://codereview.chromium.org/908883002/)
Reason for revert: Breaks Linux64 release Original issue's description: > new classes: implement new.target passing to superclass constructor. > > R=arv@chromium.org,rossberg@chromium.org > BUG=v8:3834 > LOG=N > > Committed: https://crrev.com/8aed43e82c6d2742fe5988603cb8841324cc942b > Cr-Commit-Position: refs/heads/master@{#26560} TBR=arv@chromium.org,rossberg@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:3834 Review URL: https://codereview.chromium.org/911363002 Cr-Commit-Position: refs/heads/master@{#26561}
This commit is contained in:
parent
8aed43e82c
commit
8e4ec9dd13
@ -1186,8 +1186,9 @@ static Handle<Object> ArgumentsForInlinedFunction(
|
||||
Isolate* isolate = inlined_function->GetIsolate();
|
||||
Factory* factory = isolate->factory();
|
||||
SlotRefValueBuilder slot_refs(
|
||||
frame, inlined_frame_index,
|
||||
inlined_function->shared()->internal_formal_parameter_count());
|
||||
frame,
|
||||
inlined_frame_index,
|
||||
inlined_function->shared()->formal_parameter_count());
|
||||
|
||||
int args_count = slot_refs.args_length();
|
||||
Handle<JSObject> arguments =
|
||||
|
@ -761,9 +761,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
__ SmiTag(r4);
|
||||
__ push(r4); // Smi-tagged arguments count.
|
||||
|
||||
// Push new.target.
|
||||
__ push(r3);
|
||||
|
||||
// receiver is the hole.
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ push(ip);
|
||||
@ -777,8 +774,7 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
// r2: address of last argument (caller sp)
|
||||
// r4: number of arguments (smi-tagged)
|
||||
// sp[0]: receiver
|
||||
// sp[1]: new.target
|
||||
// sp[2]: number of arguments (smi-tagged)
|
||||
// sp[1]: number of arguments (smi-tagged)
|
||||
Label loop, entry;
|
||||
__ b(&entry);
|
||||
__ bind(&loop);
|
||||
@ -791,7 +787,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
// Call the function.
|
||||
// r0: number of arguments
|
||||
// r1: constructor function
|
||||
__ add(r0, r0, Operand(1));
|
||||
ParameterCount actual(r0);
|
||||
__ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper());
|
||||
|
||||
|
@ -1488,7 +1488,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
CHECK(!has_new_target());
|
||||
// The displacement is the offset of the last parameter (if any)
|
||||
// relative to the frame pointer.
|
||||
const int kDisplacement =
|
||||
@ -1546,8 +1545,6 @@ void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// sp[4] : receiver displacement
|
||||
// sp[8] : function
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label runtime;
|
||||
__ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
@ -1576,8 +1573,6 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
|
||||
// r6 : allocated object (tagged)
|
||||
// r9 : mapped parameter count (tagged)
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
|
||||
// r1 = parameter count (tagged)
|
||||
|
||||
@ -1818,10 +1813,6 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
|
||||
// Patch the arguments.length and the parameters pointer.
|
||||
__ bind(&adaptor_frame);
|
||||
__ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
if (has_new_target()) {
|
||||
// Subtract 1 from smi-tagged arguments count.
|
||||
__ sub(r1, r1, Operand(2));
|
||||
}
|
||||
__ str(r1, MemOperand(sp, 0));
|
||||
__ add(r3, r2, Operand::PointerOffsetFromSmiKey(r1));
|
||||
__ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
|
||||
@ -2573,13 +2564,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// Pass function as original constructor.
|
||||
if (IsSuperConstructorCall()) {
|
||||
__ mov(r4, Operand(1 * kPointerSize));
|
||||
__ add(r4, r4, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ ldr(r3, MemOperand(sp, r4));
|
||||
} else {
|
||||
__ mov(r3, r1);
|
||||
}
|
||||
__ mov(r3, r1);
|
||||
|
||||
// Jump to the function-specific construct stub.
|
||||
Register jmp_reg = r4;
|
||||
|
@ -262,10 +262,6 @@ void FullCodeGenerator::Generate() {
|
||||
// function, receiver address, parameter count.
|
||||
// The stub will rewrite receiever and parameter count if the previous
|
||||
// stack frame was an arguments adapter frame.
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
: ArgumentsAccessStub::NO_NEW_TARGET;
|
||||
ArgumentsAccessStub::Type type;
|
||||
if (is_strict(language_mode())) {
|
||||
type = ArgumentsAccessStub::NEW_STRICT;
|
||||
@ -274,7 +270,7 @@ void FullCodeGenerator::Generate() {
|
||||
} else {
|
||||
type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
|
||||
}
|
||||
ArgumentsAccessStub stub(isolate(), type, has_new_target);
|
||||
ArgumentsAccessStub stub(isolate(), type);
|
||||
__ CallStub(&stub);
|
||||
|
||||
SetVar(arguments, r0, r1, r2);
|
||||
@ -454,12 +450,7 @@ void FullCodeGenerator::EmitReturnSequence() {
|
||||
// Make sure that the constant pool is not emitted inside of the return
|
||||
// sequence.
|
||||
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
|
||||
int32_t arg_count = info_->scope()->num_parameters() + 1;
|
||||
if (FLAG_experimental_classes &&
|
||||
IsSubclassConstructor(info_->function()->kind())) {
|
||||
arg_count++;
|
||||
}
|
||||
int32_t sp_delta = arg_count * kPointerSize;
|
||||
int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
|
||||
CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
|
||||
// TODO(svenpanne) The code below is sometimes 4 words, sometimes 5!
|
||||
PredictableCodeSizeScope predictable(masm_, -1);
|
||||
@ -3266,11 +3257,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
Comment cmnt(masm_, "[ SuperConstructorCall");
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ push(result_register());
|
||||
@ -3314,11 +3300,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
__ Move(r2, FeedbackVector());
|
||||
__ mov(r3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
|
||||
// TODO(dslomov): use a different stub and propagate new.target.
|
||||
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
|
||||
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
RecordJSReturnSite(expr);
|
||||
|
||||
EmitVariableAssignment(this_var, Token::INIT_CONST);
|
||||
|
@ -725,10 +725,9 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
__ Mov(x4, x0);
|
||||
__ SmiTag(x4);
|
||||
__ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
|
||||
__ Push(x4, x3, x10);
|
||||
__ Push(x4, x10);
|
||||
// sp[0]: number of arguments
|
||||
// sp[1]: new.target
|
||||
// sp[2]: receiver (the hole)
|
||||
// sp[1]: receiver (the hole)
|
||||
|
||||
|
||||
// Set up pointer to last argument.
|
||||
@ -740,8 +739,7 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
// x1: constructor function
|
||||
// x2: address of last argument (caller sp)
|
||||
// jssp[0]: receiver
|
||||
// jssp[1]: new.target
|
||||
// jssp[2]: number of arguments (smi-tagged)
|
||||
// jssp[1]: number of arguments (smi-tagged)
|
||||
// Compute the start address of the copy in x4.
|
||||
__ Add(x4, x2, Operand(x0, LSL, kPointerSizeLog2));
|
||||
Label loop, entry, done_copying_arguments;
|
||||
@ -761,7 +759,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
// Call the function.
|
||||
// x0: number of arguments
|
||||
// x1: constructor function
|
||||
__ Add(x0, x0, Operand(1)); // new.target
|
||||
ParameterCount actual(x0);
|
||||
__ InvokeFunction(x1, actual, CALL_FUNCTION, NullCallWrapper());
|
||||
|
||||
|
@ -1643,7 +1643,6 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
CHECK(!has_new_target());
|
||||
Register arg_count = ArgumentsAccessReadDescriptor::parameter_count();
|
||||
Register key = ArgumentsAccessReadDescriptor::index();
|
||||
DCHECK(arg_count.is(x0));
|
||||
@ -1700,8 +1699,6 @@ void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// jssp[8]: address of receiver argument
|
||||
// jssp[16]: function
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label runtime;
|
||||
Register caller_fp = x10;
|
||||
@ -1733,8 +1730,6 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
|
||||
//
|
||||
// Returns pointer to result object in x0.
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
// Note: arg_count_smi is an alias of param_count_smi.
|
||||
Register arg_count_smi = x3;
|
||||
Register param_count_smi = x3;
|
||||
@ -2061,11 +2056,6 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
|
||||
MemOperand(caller_fp,
|
||||
ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ SmiUntag(param_count, param_count_smi);
|
||||
if (has_new_target()) {
|
||||
// Skip new.target: it is not a part of arguments.
|
||||
__ Sub(param_count, param_count, Operand(1));
|
||||
__ SmiTag(param_count_smi, param_count);
|
||||
}
|
||||
__ Add(x10, caller_fp, Operand(param_count, LSL, kPointerSizeLog2));
|
||||
__ Add(params, x10, StandardFrameConstants::kCallerSPOffset);
|
||||
|
||||
@ -2949,13 +2939,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
||||
__ AssertUndefinedOrAllocationSite(x2, x5);
|
||||
}
|
||||
|
||||
if (IsSuperConstructorCall()) {
|
||||
__ Mov(x4, Operand(1 * kPointerSize));
|
||||
__ Add(x4, x4, Operand(x0, LSL, kPointerSizeLog2));
|
||||
__ Peek(x3, x4);
|
||||
} else {
|
||||
__ Mov(x3, function);
|
||||
}
|
||||
__ Mov(x3, function);
|
||||
|
||||
// Jump to the function-specific construct stub.
|
||||
Register jump_reg = x4;
|
||||
|
@ -262,10 +262,6 @@ void FullCodeGenerator::Generate() {
|
||||
// function, receiver address, parameter count.
|
||||
// The stub will rewrite receiver and parameter count if the previous
|
||||
// stack frame was an arguments adapter frame.
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
: ArgumentsAccessStub::NO_NEW_TARGET;
|
||||
ArgumentsAccessStub::Type type;
|
||||
if (is_strict(language_mode())) {
|
||||
type = ArgumentsAccessStub::NEW_STRICT;
|
||||
@ -274,7 +270,7 @@ void FullCodeGenerator::Generate() {
|
||||
} else {
|
||||
type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
|
||||
}
|
||||
ArgumentsAccessStub stub(isolate(), type, has_new_target);
|
||||
ArgumentsAccessStub stub(isolate(), type);
|
||||
__ CallStub(&stub);
|
||||
|
||||
SetVar(arguments, x0, x1, x2);
|
||||
@ -459,12 +455,7 @@ void FullCodeGenerator::EmitReturnSequence() {
|
||||
__ ldr_pcrel(ip0, (3 * kInstructionSize) >> kLoadLiteralScaleLog2);
|
||||
__ add(current_sp, current_sp, ip0);
|
||||
__ ret();
|
||||
int32_t arg_count = info_->scope()->num_parameters() + 1;
|
||||
if (FLAG_experimental_classes &&
|
||||
IsSubclassConstructor(info_->function()->kind())) {
|
||||
arg_count++;
|
||||
}
|
||||
__ dc64(kXRegSize * arg_count);
|
||||
__ dc64(kXRegSize * (info_->scope()->num_parameters() + 1));
|
||||
info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
|
||||
}
|
||||
}
|
||||
@ -2955,11 +2946,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
Comment cmnt(masm_, "[ SuperConstructorCall");
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ push(result_register());
|
||||
@ -3002,11 +2988,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
__ LoadObject(x2, FeedbackVector());
|
||||
__ Mov(x3, SmiFromSlot(expr->CallFeedbackSlot()));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
|
||||
// TODO(dslomov): use a different stub and propagate new.target.
|
||||
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
|
||||
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
RecordJSReturnSite(expr);
|
||||
|
||||
EmitVariableAssignment(this_var, Token::INIT_CONST);
|
||||
|
@ -249,13 +249,11 @@ class AstValue : public ZoneObject {
|
||||
F(get_template_callsite, "GetTemplateCallSite") \
|
||||
F(initialize_const_global, "initializeConstGlobal") \
|
||||
F(initialize_var_global, "initializeVarGlobal") \
|
||||
F(is_construct_call, "_IsConstructCall") \
|
||||
F(let, "let") \
|
||||
F(make_reference_error, "MakeReferenceErrorEmbedded") \
|
||||
F(make_syntax_error, "MakeSyntaxErrorEmbedded") \
|
||||
F(make_type_error, "MakeTypeErrorEmbedded") \
|
||||
F(native, "native") \
|
||||
F(new_target, "new.target") \
|
||||
F(next, "next") \
|
||||
F(proto, "__proto__") \
|
||||
F(prototype, "prototype") \
|
||||
@ -263,7 +261,8 @@ class AstValue : public ZoneObject {
|
||||
F(use_asm, "use asm") \
|
||||
F(use_strong, "use strong") \
|
||||
F(use_strict, "use strict") \
|
||||
F(value, "value")
|
||||
F(value, "value") \
|
||||
F(is_construct_call, "_IsConstructCall")
|
||||
|
||||
#define OTHER_CONSTANTS(F) \
|
||||
F(true_value) \
|
||||
|
@ -2102,7 +2102,7 @@ bool Genesis::InstallNatives() {
|
||||
DCHECK(call->is_compiled());
|
||||
|
||||
// Set the expected parameters for apply to 2; required by builtin.
|
||||
apply->shared()->set_internal_formal_parameter_count(2);
|
||||
apply->shared()->set_formal_parameter_count(2);
|
||||
|
||||
// Set the lengths for the functions to satisfy ECMA-262.
|
||||
call->shared()->set_length(1);
|
||||
|
@ -1590,13 +1590,8 @@ class ArgumentsAccessStub: public PlatformCodeStub {
|
||||
NEW_STRICT
|
||||
};
|
||||
|
||||
enum HasNewTarget { NO_NEW_TARGET, HAS_NEW_TARGET };
|
||||
|
||||
ArgumentsAccessStub(Isolate* isolate, Type type,
|
||||
HasNewTarget has_new_target = NO_NEW_TARGET)
|
||||
: PlatformCodeStub(isolate) {
|
||||
minor_key_ =
|
||||
TypeBits::encode(type) | HasNewTargetBits::encode(has_new_target);
|
||||
ArgumentsAccessStub(Isolate* isolate, Type type) : PlatformCodeStub(isolate) {
|
||||
minor_key_ = TypeBits::encode(type);
|
||||
}
|
||||
|
||||
CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
|
||||
@ -1608,9 +1603,6 @@ class ArgumentsAccessStub: public PlatformCodeStub {
|
||||
|
||||
private:
|
||||
Type type() const { return TypeBits::decode(minor_key_); }
|
||||
bool has_new_target() const {
|
||||
return HasNewTargetBits::decode(minor_key_) == HAS_NEW_TARGET;
|
||||
}
|
||||
|
||||
void GenerateReadElement(MacroAssembler* masm);
|
||||
void GenerateNewStrict(MacroAssembler* masm);
|
||||
@ -1620,7 +1612,6 @@ class ArgumentsAccessStub: public PlatformCodeStub {
|
||||
void PrintName(std::ostream& os) const OVERRIDE; // NOLINT
|
||||
|
||||
class TypeBits : public BitField<Type, 0, 2> {};
|
||||
class HasNewTargetBits : public BitField<HasNewTarget, 2, 1> {};
|
||||
|
||||
DEFINE_PLATFORM_CODE_STUB(ArgumentsAccess, PlatformCodeStub);
|
||||
};
|
||||
@ -1702,13 +1693,9 @@ class CallConstructStub: public PlatformCodeStub {
|
||||
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> {};
|
||||
class FlagBits : public BitField<CallConstructorFlags, 0, 1> {};
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(CallConstruct);
|
||||
DEFINE_PLATFORM_CODE_STUB(CallConstruct, PlatformCodeStub);
|
||||
|
@ -24,8 +24,7 @@ class ParameterCount BASE_EMBEDDED {
|
||||
explicit ParameterCount(int immediate)
|
||||
: reg_(no_reg), immediate_(immediate) { }
|
||||
explicit ParameterCount(Handle<JSFunction> f)
|
||||
: reg_(no_reg),
|
||||
immediate_(f->shared()->internal_formal_parameter_count()) {}
|
||||
: reg_(no_reg), immediate_(f->shared()->formal_parameter_count()) { }
|
||||
|
||||
bool is_reg() const { return !reg_.is(no_reg); }
|
||||
bool is_immediate() const { return !is_reg(); }
|
||||
|
@ -619,12 +619,7 @@ static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
|
||||
bool is_toplevel,
|
||||
Handle<Script> script) {
|
||||
function_info->set_length(lit->parameter_count());
|
||||
if (FLAG_experimental_classes && IsSubclassConstructor(lit->kind())) {
|
||||
function_info->set_internal_formal_parameter_count(lit->parameter_count() +
|
||||
1);
|
||||
} else {
|
||||
function_info->set_internal_formal_parameter_count(lit->parameter_count());
|
||||
}
|
||||
function_info->set_formal_parameter_count(lit->parameter_count());
|
||||
function_info->set_script(*script);
|
||||
function_info->set_function_token_position(lit->function_token_position());
|
||||
function_info->set_start_position(lit->start_position());
|
||||
|
@ -397,9 +397,7 @@ bool JSGenericLowering::TryLowerDirectJSCall(Node* node) {
|
||||
Handle<Object> func = function_const.Value().handle();
|
||||
if (!func->IsJSFunction()) return false; // not a function.
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(func);
|
||||
if (arg_count != function->shared()->internal_formal_parameter_count()) {
|
||||
return false;
|
||||
}
|
||||
if (arg_count != function->shared()->formal_parameter_count()) return false;
|
||||
|
||||
// Check the receiver doesn't need to be wrapped.
|
||||
Node* receiver = node->InputAt(1);
|
||||
|
@ -51,7 +51,7 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
|
||||
// plus the receiver.
|
||||
SharedFunctionInfo* shared = info->closure()->shared();
|
||||
return GetJSCallDescriptor(zone, info->is_osr(),
|
||||
1 + shared->internal_formal_parameter_count(),
|
||||
1 + shared->formal_parameter_count(),
|
||||
CallDescriptor::kNoFlags);
|
||||
}
|
||||
if (info->code_stub() != NULL) {
|
||||
|
@ -810,12 +810,6 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
return Handle<Code>::null();
|
||||
}
|
||||
|
||||
// TODO(dslomov): support turbo optimization of subclass constructors.
|
||||
if (IsSubclassConstructor(shared->kind())) {
|
||||
shared->DisableOptimization(kSuperReference);
|
||||
return Handle<Code>::null();
|
||||
}
|
||||
|
||||
ZonePool zone_pool;
|
||||
SmartPointer<PipelineStatistics> pipeline_statistics;
|
||||
|
||||
|
@ -927,8 +927,7 @@ void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
||||
output_frame->SetTop(top_address);
|
||||
|
||||
// Compute the incoming parameter translation.
|
||||
int parameter_count =
|
||||
function->shared()->internal_formal_parameter_count() + 1;
|
||||
int parameter_count = function->shared()->formal_parameter_count() + 1;
|
||||
unsigned output_offset = output_frame_size;
|
||||
unsigned input_offset = input_frame_size;
|
||||
for (int i = 0; i < parameter_count; ++i) {
|
||||
@ -2725,8 +2724,7 @@ unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
|
||||
CHECK_EQ(Smi::cast(function), Smi::FromInt(StackFrame::STUB));
|
||||
return 0;
|
||||
}
|
||||
unsigned arguments =
|
||||
function->shared()->internal_formal_parameter_count() + 1;
|
||||
unsigned arguments = function->shared()->formal_parameter_count() + 1;
|
||||
return arguments * kPointerSize;
|
||||
}
|
||||
|
||||
@ -2863,7 +2861,7 @@ unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
|
||||
int FrameDescription::ComputeParametersCount() {
|
||||
switch (type_) {
|
||||
case StackFrame::JAVA_SCRIPT:
|
||||
return function_->shared()->internal_formal_parameter_count();
|
||||
return function_->shared()->formal_parameter_count();
|
||||
case StackFrame::ARGUMENTS_ADAPTOR: {
|
||||
// Last slot contains number of incomming arguments as a smi.
|
||||
// Can't use GetExpression(0) because it would cause infinite recursion.
|
||||
|
@ -2103,7 +2103,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
|
||||
|
||||
// Set integer fields (smi or int, depending on the architecture).
|
||||
share->set_length(0);
|
||||
share->set_internal_formal_parameter_count(0);
|
||||
share->set_formal_parameter_count(0);
|
||||
share->set_expected_nof_properties(0);
|
||||
share->set_num_literals(0);
|
||||
share->set_start_position_and_type(0);
|
||||
|
@ -754,7 +754,7 @@ int JavaScriptFrame::GetNumberOfIncomingArguments() const {
|
||||
DCHECK(can_access_heap_objects() &&
|
||||
isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
|
||||
|
||||
return function()->shared()->internal_formal_parameter_count();
|
||||
return function()->shared()->formal_parameter_count();
|
||||
}
|
||||
|
||||
|
||||
@ -1310,7 +1310,7 @@ void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
|
||||
int actual = ComputeParametersCount();
|
||||
int expected = -1;
|
||||
JSFunction* function = this->function();
|
||||
expected = function->shared()->internal_formal_parameter_count();
|
||||
expected = function->shared()->formal_parameter_count();
|
||||
|
||||
PrintIndex(accumulator, mode, index);
|
||||
accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
|
||||
|
@ -1652,8 +1652,8 @@ void FullCodeGenerator::VisitNativeFunctionLiteral(
|
||||
|
||||
// Copy the function data to the shared function info.
|
||||
shared->set_function_data(fun->shared()->function_data());
|
||||
int parameters = fun->shared()->internal_formal_parameter_count();
|
||||
shared->set_internal_formal_parameter_count(parameters);
|
||||
int parameters = fun->shared()->formal_parameter_count();
|
||||
shared->set_formal_parameter_count(parameters);
|
||||
|
||||
EmitNewClosure(shared, false);
|
||||
}
|
||||
|
@ -527,11 +527,9 @@ enum CallFunctionFlags {
|
||||
|
||||
|
||||
enum CallConstructorFlags {
|
||||
NO_CALL_CONSTRUCTOR_FLAGS = 0,
|
||||
NO_CALL_CONSTRUCTOR_FLAGS,
|
||||
// The call target is cached in the instruction stream.
|
||||
RECORD_CONSTRUCTOR_TARGET = 1,
|
||||
SUPER_CONSTRUCTOR_CALL = 1 << 1,
|
||||
SUPER_CALL_RECORD_TARGET = SUPER_CONSTRUCTOR_CALL | RECORD_CONSTRUCTOR_TARGET
|
||||
RECORD_CONSTRUCTOR_TARGET
|
||||
};
|
||||
|
||||
|
||||
|
@ -2393,10 +2393,8 @@ class HInvokeFunction FINAL : public HBinaryCall {
|
||||
int argument_count)
|
||||
: HBinaryCall(context, function, argument_count),
|
||||
known_function_(known_function) {
|
||||
formal_parameter_count_ =
|
||||
known_function.is_null()
|
||||
? 0
|
||||
: known_function->shared()->internal_formal_parameter_count();
|
||||
formal_parameter_count_ = known_function.is_null()
|
||||
? 0 : known_function->shared()->formal_parameter_count();
|
||||
has_stack_check_ = !known_function.is_null() &&
|
||||
(known_function->code()->kind() == Code::FUNCTION ||
|
||||
known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
|
||||
|
@ -4281,11 +4281,6 @@ void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::BuildGraph() {
|
||||
if (IsSubclassConstructor(current_info()->function()->kind())) {
|
||||
Bailout(kSuperReference);
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope* scope = current_info()->scope();
|
||||
SetUpScope(scope);
|
||||
|
||||
@ -7570,8 +7565,7 @@ HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction(
|
||||
HValue* target = Add<HConstant>(jsfun);
|
||||
// For constant functions, we try to avoid calling the
|
||||
// argument adaptor and instead call the function directly
|
||||
int formal_parameter_count =
|
||||
jsfun->shared()->internal_formal_parameter_count();
|
||||
int formal_parameter_count = jsfun->shared()->formal_parameter_count();
|
||||
bool dont_adapt_arguments =
|
||||
(formal_parameter_count ==
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel);
|
||||
|
@ -519,9 +519,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
__ push(eax);
|
||||
__ SmiUntag(eax);
|
||||
|
||||
// Push new.target.
|
||||
__ push(edx);
|
||||
|
||||
// receiver is the hole.
|
||||
__ push(Immediate(masm->isolate()->factory()->the_hole_value()));
|
||||
|
||||
@ -538,7 +535,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
__ dec(ecx);
|
||||
__ j(greater_equal, &loop);
|
||||
|
||||
__ inc(eax); // Pushed new.target.
|
||||
ParameterCount actual(eax);
|
||||
__ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
|
||||
|
||||
|
@ -738,7 +738,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
CHECK(!has_new_target());
|
||||
// The key is in edx and the parameter count is in eax.
|
||||
DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(eax.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
@ -805,8 +804,6 @@ void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// esp[8] : receiver displacement
|
||||
// esp[12] : function
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label runtime;
|
||||
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
@ -835,8 +832,6 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
|
||||
// ebx = parameter count (tagged)
|
||||
__ mov(ebx, Operand(esp, 1 * kPointerSize));
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
// TODO(rossberg): Factor out some of the bits that are shared with the other
|
||||
// Generate* functions.
|
||||
@ -1076,15 +1071,9 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
|
||||
// Patch the arguments.length and the parameters pointer.
|
||||
__ bind(&adaptor_frame);
|
||||
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
if (has_new_target()) {
|
||||
// Subtract 1 from smi-tagged arguments count.
|
||||
__ sub(ecx, Immediate(2));
|
||||
}
|
||||
|
||||
__ mov(Operand(esp, 1 * kPointerSize), ecx);
|
||||
__ lea(edx, Operand(edx, ecx, times_2,
|
||||
StandardFrameConstants::kCallerSPOffset));
|
||||
__ mov(Operand(esp, 1 * kPointerSize), ecx);
|
||||
__ mov(Operand(esp, 2 * kPointerSize), edx);
|
||||
|
||||
// Try the new space allocation. Start out with computing the size of
|
||||
@ -2160,12 +2149,8 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
||||
__ AssertUndefinedOrAllocationSite(ebx);
|
||||
}
|
||||
|
||||
if (IsSuperConstructorCall()) {
|
||||
__ mov(edx, Operand(esp, eax, times_pointer_size, 2 * kPointerSize));
|
||||
} else {
|
||||
// Pass original constructor to construct stub.
|
||||
__ mov(edx, edi);
|
||||
}
|
||||
// Pass original constructor to construct stub.
|
||||
__ mov(edx, edi);
|
||||
|
||||
// Jump to the function-specific construct stub.
|
||||
Register jmp_reg = ecx;
|
||||
|
@ -212,8 +212,7 @@ void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
|
||||
|
||||
bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
|
||||
int parameter_count =
|
||||
function->shared()->internal_formal_parameter_count() + 1;
|
||||
int parameter_count = function->shared()->formal_parameter_count() + 1;
|
||||
unsigned input_frame_size = input_->GetFrameSize();
|
||||
unsigned alignment_state_offset =
|
||||
input_frame_size - parameter_count * kPointerSize -
|
||||
|
@ -264,11 +264,7 @@ void FullCodeGenerator::Generate() {
|
||||
} else {
|
||||
type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
|
||||
}
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
: ArgumentsAccessStub::NO_NEW_TARGET;
|
||||
ArgumentsAccessStub stub(isolate(), type, has_new_target);
|
||||
ArgumentsAccessStub stub(isolate(), type);
|
||||
__ CallStub(&stub);
|
||||
|
||||
SetVar(arguments, eax, ebx, edx);
|
||||
@ -417,12 +413,7 @@ void FullCodeGenerator::EmitReturnSequence() {
|
||||
int no_frame_start = masm_->pc_offset();
|
||||
__ pop(ebp);
|
||||
|
||||
int arg_count = info_->scope()->num_parameters() + 1;
|
||||
if (FLAG_experimental_classes &&
|
||||
IsSubclassConstructor(info_->function()->kind())) {
|
||||
arg_count++;
|
||||
}
|
||||
int arguments_bytes = arg_count * kPointerSize;
|
||||
int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
|
||||
__ Ret(arguments_bytes, ecx);
|
||||
// Check that the size of the code used for returning is large enough
|
||||
// for the debugger's requirements.
|
||||
@ -3146,10 +3137,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(eax, new_target_var);
|
||||
__ push(eax);
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ push(result_register());
|
||||
@ -3191,11 +3178,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
__ LoadHeapObject(ebx, FeedbackVector());
|
||||
__ mov(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot())));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
|
||||
// TODO(dslomov): use a different stub and propagate new.target.
|
||||
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
|
||||
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
RecordJSReturnSite(expr);
|
||||
|
||||
EmitVariableAssignment(this_var, Token::INIT_CONST);
|
||||
|
@ -1237,8 +1237,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
return compiler.CompileLoadCallback(lookup->name(), call_optimization,
|
||||
lookup->GetAccessorIndex());
|
||||
}
|
||||
int expected_arguments =
|
||||
function->shared()->internal_formal_parameter_count();
|
||||
int expected_arguments = function->shared()->formal_parameter_count();
|
||||
return compiler.CompileLoadViaGetter(
|
||||
lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
|
||||
}
|
||||
@ -1744,8 +1743,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
call_optimization,
|
||||
lookup->GetAccessorIndex());
|
||||
}
|
||||
int expected_arguments =
|
||||
function->shared()->internal_formal_parameter_count();
|
||||
int expected_arguments = function->shared()->formal_parameter_count();
|
||||
return compiler.CompileStoreViaSetter(receiver, lookup->name(),
|
||||
lookup->GetAccessorIndex(),
|
||||
expected_arguments);
|
||||
|
@ -5718,7 +5718,7 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, deserialized, kDeserialized)
|
||||
|
||||
#if V8_HOST_ARCH_32_BIT
|
||||
SMI_ACCESSORS(SharedFunctionInfo, length, kLengthOffset)
|
||||
SMI_ACCESSORS(SharedFunctionInfo, internal_formal_parameter_count,
|
||||
SMI_ACCESSORS(SharedFunctionInfo, formal_parameter_count,
|
||||
kFormalParameterCountOffset)
|
||||
SMI_ACCESSORS(SharedFunctionInfo, expected_nof_properties,
|
||||
kExpectedNofPropertiesOffset)
|
||||
@ -5766,7 +5766,8 @@ SMI_ACCESSORS(SharedFunctionInfo, profiler_ticks, kProfilerTicksOffset)
|
||||
|
||||
|
||||
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, length, kLengthOffset)
|
||||
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, internal_formal_parameter_count,
|
||||
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
|
||||
formal_parameter_count,
|
||||
kFormalParameterCountOffset)
|
||||
|
||||
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
|
||||
@ -5898,7 +5899,7 @@ bool Script::HasValidSource() {
|
||||
|
||||
void SharedFunctionInfo::DontAdaptArguments() {
|
||||
DCHECK(code()->kind() == Code::BUILTIN);
|
||||
set_internal_formal_parameter_count(kDontAdaptArgumentsSentinel);
|
||||
set_formal_parameter_count(kDontAdaptArgumentsSentinel);
|
||||
}
|
||||
|
||||
|
||||
@ -6079,8 +6080,8 @@ bool JSFunction::IsFromExtensionScript() {
|
||||
|
||||
|
||||
bool JSFunction::NeedsArgumentsAdaption() {
|
||||
return shared()->internal_formal_parameter_count() !=
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel;
|
||||
return shared()->formal_parameter_count() !=
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6770,11 +6770,9 @@ class SharedFunctionInfo: public HeapObject {
|
||||
inline int length() const;
|
||||
inline void set_length(int value);
|
||||
|
||||
// [internal formal parameter count]: The declared number of parameters.
|
||||
// For subclass constructors, also includes new.target.
|
||||
// The size of function's frame is internal_formal_parameter_count + 1.
|
||||
inline int internal_formal_parameter_count() const;
|
||||
inline void set_internal_formal_parameter_count(int value);
|
||||
// [formal parameter count]: The declared number of parameters.
|
||||
inline int formal_parameter_count() const;
|
||||
inline void set_formal_parameter_count(int value);
|
||||
|
||||
// Set the formal parameter count so the function code will be
|
||||
// called without using argument adaptor frames.
|
||||
|
@ -117,7 +117,7 @@ RUNTIME_FUNCTION(Runtime_DefineClass) {
|
||||
constructor->shared()->set_name(*name_string);
|
||||
|
||||
if (FLAG_experimental_classes) {
|
||||
if (!super_class->IsTheHole()) {
|
||||
if (!super_class->IsTheHole() && !super_class->IsNull()) {
|
||||
Handle<Code> stub(isolate->builtins()->JSConstructStubForDerived());
|
||||
constructor->shared()->set_construct_stub(*stub);
|
||||
}
|
||||
|
@ -271,8 +271,8 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
|
||||
target_shared->set_scope_info(source_shared->scope_info());
|
||||
target_shared->set_length(source_shared->length());
|
||||
target_shared->set_feedback_vector(source_shared->feedback_vector());
|
||||
target_shared->set_internal_formal_parameter_count(
|
||||
source_shared->internal_formal_parameter_count());
|
||||
target_shared->set_formal_parameter_count(
|
||||
source_shared->formal_parameter_count());
|
||||
target_shared->set_script(source_shared->script());
|
||||
target_shared->set_start_position_and_type(
|
||||
source_shared->start_position_and_type());
|
||||
@ -383,7 +383,7 @@ static SmartArrayPointer<Handle<Object> > GetCallerArguments(Isolate* isolate,
|
||||
JSFunction* inlined_function = functions[inlined_jsframe_index];
|
||||
SlotRefValueBuilder slot_refs(
|
||||
frame, inlined_jsframe_index,
|
||||
inlined_function->shared()->internal_formal_parameter_count());
|
||||
inlined_function->shared()->formal_parameter_count());
|
||||
|
||||
int args_count = slot_refs.args_length();
|
||||
|
||||
|
@ -1245,6 +1245,10 @@ static Object* Runtime_NewObjectHelper(Isolate* isolate,
|
||||
Handle<Object> constructor,
|
||||
Handle<Object> original_constructor,
|
||||
Handle<AllocationSite> site) {
|
||||
// TODO(dslomov): implement prototype rewiring.
|
||||
// The check below is a sanity check.
|
||||
CHECK(*constructor == *original_constructor);
|
||||
|
||||
// If the constructor isn't a proper function we throw a type error.
|
||||
if (!constructor->IsJSFunction()) {
|
||||
Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
|
||||
@ -1254,11 +1258,6 @@ static Object* Runtime_NewObjectHelper(Isolate* isolate,
|
||||
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
|
||||
|
||||
CHECK(original_constructor->IsJSFunction());
|
||||
Handle<JSFunction> original_function =
|
||||
Handle<JSFunction>::cast(original_constructor);
|
||||
|
||||
|
||||
// If function should not have prototype, construction is not allowed. In this
|
||||
// case generated code bailouts here, since function has no initial_map.
|
||||
if (!function->should_have_prototype() && !function->shared()->bound()) {
|
||||
@ -1301,18 +1300,6 @@ static Object* Runtime_NewObjectHelper(Isolate* isolate,
|
||||
result = isolate->factory()->NewJSObjectWithMemento(function, site);
|
||||
}
|
||||
|
||||
// Set up the prototoype using original function.
|
||||
// TODO(dslomov): instead of setting the __proto__,
|
||||
// use and cache the correct map.
|
||||
if (*original_function != *function) {
|
||||
if (original_function->has_instance_prototype()) {
|
||||
Handle<Object> prototype =
|
||||
handle(original_function->instance_prototype(), isolate);
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, JSObject::SetPrototype(result, prototype, false));
|
||||
}
|
||||
}
|
||||
|
||||
isolate->counters()->constructed_objects()->Increment();
|
||||
isolate->counters()->constructed_objects_runtime()->Increment();
|
||||
|
||||
|
@ -356,12 +356,11 @@ static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
|
||||
Handle<JSFunction> callee,
|
||||
Object** parameters,
|
||||
int argument_count) {
|
||||
CHECK(!IsSubclassConstructor(callee->shared()->kind()));
|
||||
Handle<JSObject> result =
|
||||
isolate->factory()->NewArgumentsObject(callee, argument_count);
|
||||
|
||||
// Allocate the elements if needed.
|
||||
int parameter_count = callee->shared()->internal_formal_parameter_count();
|
||||
int parameter_count = callee->shared()->formal_parameter_count();
|
||||
if (argument_count > 0) {
|
||||
if (parameter_count > 0) {
|
||||
int mapped_count = Min(argument_count, parameter_count);
|
||||
|
@ -148,7 +148,6 @@ void Scope::SetDefaults(ScopeType scope_type,
|
||||
scope_name_ = ast_value_factory_->empty_string();
|
||||
dynamics_ = NULL;
|
||||
receiver_ = NULL;
|
||||
new_target_ = nullptr;
|
||||
function_ = NULL;
|
||||
arguments_ = NULL;
|
||||
illegal_redecl_ = NULL;
|
||||
@ -288,7 +287,7 @@ bool Scope::Analyze(CompilationInfo* info) {
|
||||
}
|
||||
|
||||
|
||||
void Scope::Initialize(bool subclass_constructor) {
|
||||
void Scope::Initialize(bool uninitialized_this) {
|
||||
DCHECK(!already_resolved());
|
||||
|
||||
// Add this scope as a new inner scope of the outer scope.
|
||||
@ -308,22 +307,14 @@ void Scope::Initialize(bool subclass_constructor) {
|
||||
// such parameter is 'this' which is passed on the stack when
|
||||
// invoking scripts
|
||||
if (is_declaration_scope()) {
|
||||
DCHECK(!subclass_constructor || is_function_scope());
|
||||
DCHECK(FLAG_experimental_classes || !subclass_constructor);
|
||||
DCHECK(!uninitialized_this || is_function_scope());
|
||||
DCHECK(FLAG_experimental_classes || !uninitialized_this);
|
||||
Variable* var = variables_.Declare(
|
||||
this, ast_value_factory_->this_string(),
|
||||
subclass_constructor ? CONST : VAR, false, Variable::THIS,
|
||||
subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
|
||||
uninitialized_this ? CONST : VAR, false, Variable::THIS,
|
||||
uninitialized_this ? kNeedsInitialization : kCreatedInitialized);
|
||||
var->AllocateTo(Variable::PARAMETER, -1);
|
||||
receiver_ = var;
|
||||
|
||||
if (subclass_constructor) {
|
||||
new_target_ = variables_.Declare(
|
||||
this, ast_value_factory_->new_target_string(), CONST, false,
|
||||
Variable::NEW_TARGET, kCreatedInitialized);
|
||||
new_target_->AllocateTo(Variable::PARAMETER, -2);
|
||||
new_target_->set_is_used();
|
||||
}
|
||||
} else {
|
||||
DCHECK(outer_scope() != NULL);
|
||||
receiver_ = outer_scope()->receiver();
|
||||
@ -1210,10 +1201,15 @@ bool Scope::MustAllocate(Variable* var) {
|
||||
// Give var a read/write use if there is a chance it might be accessed
|
||||
// via an eval() call. This is only possible if the variable has a
|
||||
// visible name.
|
||||
if ((var->is_this() || var->is_new_target() || !var->raw_name()->IsEmpty()) &&
|
||||
(var->has_forced_context_allocation() || scope_calls_eval_ ||
|
||||
inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() ||
|
||||
is_block_scope() || is_module_scope() || is_script_scope())) {
|
||||
if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
|
||||
(var->has_forced_context_allocation() ||
|
||||
scope_calls_eval_ ||
|
||||
inner_scope_calls_eval_ ||
|
||||
scope_contains_with_ ||
|
||||
is_catch_scope() ||
|
||||
is_block_scope() ||
|
||||
is_module_scope() ||
|
||||
is_script_scope())) {
|
||||
var->set_is_used();
|
||||
if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned();
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class Scope: public ZoneObject {
|
||||
scope_name_ = scope_name;
|
||||
}
|
||||
|
||||
void Initialize(bool subclass_constructor = false);
|
||||
void Initialize(bool uninitialized_this = false);
|
||||
|
||||
// Checks if the block scope is redundant, i.e. it does not contain any
|
||||
// block scoped declarations. In that case it is removed from the scope
|
||||
@ -343,12 +343,9 @@ class Scope: public ZoneObject {
|
||||
// The language mode of this scope.
|
||||
LanguageMode language_mode() const { return language_mode_; }
|
||||
|
||||
// The variable corresponding to the 'this' value.
|
||||
// The variable corresponding the 'this' value.
|
||||
Variable* receiver() { return receiver_; }
|
||||
|
||||
// The variable corresponding to the 'new.target' value.
|
||||
Variable* new_target_var() { return new_target_; }
|
||||
|
||||
// The variable holding the function literal for named function
|
||||
// literals, or NULL. Only valid for function scopes.
|
||||
VariableDeclaration* function() const {
|
||||
@ -520,8 +517,6 @@ class Scope: public ZoneObject {
|
||||
Variable* receiver_;
|
||||
// Function variable, if any; function scopes only.
|
||||
VariableDeclaration* function_;
|
||||
// new.target variable, function scopes only.
|
||||
Variable* new_target_;
|
||||
// Convenience variable; function scopes only.
|
||||
Variable* arguments_;
|
||||
// Interface; module scopes only.
|
||||
|
@ -19,7 +19,11 @@ namespace internal {
|
||||
|
||||
class Variable: public ZoneObject {
|
||||
public:
|
||||
enum Kind { NORMAL, THIS, NEW_TARGET, ARGUMENTS };
|
||||
enum Kind {
|
||||
NORMAL,
|
||||
THIS,
|
||||
ARGUMENTS
|
||||
};
|
||||
|
||||
enum Location {
|
||||
// Before and during variable allocation, a variable whose location is
|
||||
@ -101,7 +105,6 @@ class Variable: public ZoneObject {
|
||||
}
|
||||
|
||||
bool is_this() const { return kind_ == THIS; }
|
||||
bool is_new_target() const { return kind_ == NEW_TARGET; }
|
||||
bool is_arguments() const { return kind_ == ARGUMENTS; }
|
||||
|
||||
// True if the variable is named eval and not known to be shadowed.
|
||||
|
@ -516,9 +516,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
__ Push(rax);
|
||||
__ SmiToInteger32(rax, rax);
|
||||
|
||||
// Push new.target
|
||||
__ Push(rdx);
|
||||
|
||||
// receiver is the hole.
|
||||
__ Push(masm->isolate()->factory()->the_hole_value());
|
||||
|
||||
@ -536,7 +533,6 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
|
||||
__ j(greater_equal, &loop);
|
||||
|
||||
// Call the function.
|
||||
__ incp(rax); // Pushed new.target.
|
||||
ParameterCount actual(rax);
|
||||
__ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
|
||||
|
||||
|
@ -539,7 +539,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
CHECK(!has_new_target());
|
||||
// The key is in rdx and the parameter count is in rax.
|
||||
DCHECK(rdx.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(rax.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
@ -607,8 +606,6 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
|
||||
// rbx: the mapped parameter count (untagged)
|
||||
// rax: the allocated object (tagged).
|
||||
|
||||
CHECK(!has_new_target());
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
|
||||
StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
||||
@ -822,7 +819,6 @@ void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// rsp[8] : number of parameters
|
||||
// rsp[16] : receiver displacement
|
||||
// rsp[24] : function
|
||||
CHECK(!has_new_target());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label runtime;
|
||||
@ -932,11 +928,6 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
|
||||
// Patch the arguments.length and the parameters pointer.
|
||||
__ bind(&adaptor_frame);
|
||||
__ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
if (has_new_target()) {
|
||||
// Subtract 1 from smi-tagged arguments count.
|
||||
__ subp(rcx, Immediate(2));
|
||||
}
|
||||
__ movp(args.GetArgumentOperand(2), rcx);
|
||||
__ SmiToInteger64(rcx, rcx);
|
||||
__ leap(rdx, Operand(rdx, rcx, times_pointer_size,
|
||||
@ -2027,11 +2018,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
// Pass original constructor to construct stub.
|
||||
if (IsSuperConstructorCall()) {
|
||||
__ movp(rdx, Operand(rsp, rax, times_pointer_size, 2 * kPointerSize));
|
||||
} else {
|
||||
__ movp(rdx, rdi);
|
||||
}
|
||||
__ movp(rdx, rdi);
|
||||
|
||||
// Jump to the function-specific construct stub.
|
||||
Register jmp_reg = rcx;
|
||||
|
@ -254,11 +254,6 @@ void FullCodeGenerator::Generate() {
|
||||
// function, receiver address, parameter count.
|
||||
// The stub will rewrite receiver and parameter count if the previous
|
||||
// stack frame was an arguments adapter frame.
|
||||
|
||||
ArgumentsAccessStub::HasNewTarget has_new_target =
|
||||
IsSubclassConstructor(info->function()->kind())
|
||||
? ArgumentsAccessStub::HAS_NEW_TARGET
|
||||
: ArgumentsAccessStub::NO_NEW_TARGET;
|
||||
ArgumentsAccessStub::Type type;
|
||||
if (is_strict(language_mode())) {
|
||||
type = ArgumentsAccessStub::NEW_STRICT;
|
||||
@ -267,7 +262,7 @@ void FullCodeGenerator::Generate() {
|
||||
} else {
|
||||
type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
|
||||
}
|
||||
ArgumentsAccessStub stub(isolate(), type, has_new_target);
|
||||
ArgumentsAccessStub stub(isolate(), type);
|
||||
__ CallStub(&stub);
|
||||
|
||||
SetVar(arguments, rax, rbx, rdx);
|
||||
@ -421,12 +416,7 @@ void FullCodeGenerator::EmitReturnSequence() {
|
||||
__ popq(rbp);
|
||||
int no_frame_start = masm_->pc_offset();
|
||||
|
||||
int arg_count = info_->scope()->num_parameters() + 1;
|
||||
if (FLAG_experimental_classes &&
|
||||
IsSubclassConstructor(info_->function()->kind())) {
|
||||
arg_count++;
|
||||
}
|
||||
int arguments_bytes = arg_count * kPointerSize;
|
||||
int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
|
||||
__ Ret(arguments_bytes, rcx);
|
||||
|
||||
// Add padding that will be overwritten by a debugger breakpoint. We
|
||||
@ -3152,10 +3142,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
__ Push(result_register());
|
||||
@ -3200,14 +3186,11 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
__ Move(rdx, SmiFromSlot(expr->CallFeedbackSlot()));
|
||||
|
||||
// TODO(dslomov): use a different stub and propagate new.target.
|
||||
CallConstructStub stub(isolate(), SUPER_CALL_RECORD_TARGET);
|
||||
CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
|
||||
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
RecordJSReturnSite(expr);
|
||||
|
||||
|
||||
EmitVariableAssignment(this_var, Token::INIT_CONST);
|
||||
context()->Plug(rax);
|
||||
}
|
||||
|
@ -5,223 +5,63 @@
|
||||
// Flags: --experimental-classes --harmony-classes
|
||||
|
||||
'use strict';
|
||||
(function TestArgumentsAccess() {
|
||||
class Base {
|
||||
constructor() {
|
||||
assertEquals(2, arguments.length);
|
||||
assertEquals(1, arguments[0]);
|
||||
assertEquals(2, arguments[1]);
|
||||
|
||||
class Base {
|
||||
constructor(a, b) {
|
||||
let o = new Object();
|
||||
o.prp = a + b;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
class Subclass extends Base {
|
||||
constructor(a, b) {
|
||||
var exn;
|
||||
try {
|
||||
this.prp1 = 3;
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
assertTrue(exn instanceof ReferenceError);
|
||||
super(a, b);
|
||||
assertSame(a + b, this.prp);
|
||||
assertSame(undefined, this.prp1);
|
||||
assertFalse(this.hasOwnProperty("prp1"));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
let b = new Base(1,2);
|
||||
let b = new Base(1, 2);
|
||||
assertSame(3, b.prp);
|
||||
|
||||
class Subclass extends Base {
|
||||
constructor() {
|
||||
assertEquals(2, arguments.length);
|
||||
assertEquals(3, arguments[0]);
|
||||
assertEquals(4, arguments[1]);
|
||||
super(1,2);
|
||||
}
|
||||
|
||||
let s = new Subclass(2, -1);
|
||||
assertSame(1, s.prp);
|
||||
assertSame(undefined, s.prp1);
|
||||
assertFalse(s.hasOwnProperty("prp1"));
|
||||
|
||||
class Subclass2 extends Base {
|
||||
constructor(x) {
|
||||
super(1,2);
|
||||
|
||||
if (x < 0) return;
|
||||
|
||||
let called = false;
|
||||
function tmp() { called = true; return 3; }
|
||||
var exn = null;
|
||||
try {
|
||||
super(tmp(),4);
|
||||
} catch(e) { exn = e; }
|
||||
assertTrue(exn !== null);
|
||||
assertFalse(called);
|
||||
}
|
||||
}
|
||||
|
||||
let s = new Subclass(3,4);
|
||||
assertEquals(0, Subclass.length);
|
||||
var s2 = new Subclass2(1);
|
||||
assertSame(3, s2.prp);
|
||||
|
||||
class Subclass2 extends Base {
|
||||
constructor(x,y) {
|
||||
assertEquals(2, arguments.length);
|
||||
assertEquals(3, arguments[0]);
|
||||
assertEquals(4, arguments[1]);
|
||||
super(1,2);
|
||||
}
|
||||
}
|
||||
var s3 = new Subclass2(-1);
|
||||
assertSame(3, s3.prp);
|
||||
|
||||
let s2 = new Subclass2(3,4);
|
||||
assertEquals(2, Subclass2.length);
|
||||
}());
|
||||
|
||||
(function TestThisAccessRestriction() {
|
||||
class Base {
|
||||
constructor(a, b) {
|
||||
let o = new Object();
|
||||
o.prp = a + b;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
class Subclass extends Base {
|
||||
constructor(a, b) {
|
||||
var exn;
|
||||
try {
|
||||
this.prp1 = 3;
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
assertTrue(exn instanceof ReferenceError);
|
||||
super(a, b);
|
||||
assertSame(a + b, this.prp);
|
||||
assertSame(undefined, this.prp1);
|
||||
assertFalse(this.hasOwnProperty("prp1"));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
let b = new Base(1, 2);
|
||||
assertSame(3, b.prp);
|
||||
|
||||
|
||||
let s = new Subclass(2, -1);
|
||||
assertSame(1, s.prp);
|
||||
assertSame(undefined, s.prp1);
|
||||
assertFalse(s.hasOwnProperty("prp1"));
|
||||
|
||||
class Subclass2 extends Base {
|
||||
constructor(x) {
|
||||
super(1,2);
|
||||
|
||||
if (x < 0) return;
|
||||
|
||||
let called = false;
|
||||
function tmp() { called = true; return 3; }
|
||||
var exn = null;
|
||||
try {
|
||||
super(tmp(),4);
|
||||
} catch (e) { exn = e; }
|
||||
assertTrue(exn instanceof ReferenceError);
|
||||
// TODO(dslomov): should be 'true'.
|
||||
assertFalse(called);
|
||||
}
|
||||
}
|
||||
|
||||
var s2 = new Subclass2(1);
|
||||
assertSame(3, s2.prp);
|
||||
|
||||
var s3 = new Subclass2(-1);
|
||||
assertSame(3, s3.prp);
|
||||
|
||||
assertThrows(function() { Subclass.call(new Object(), 1, 2); }, TypeError);
|
||||
assertThrows(function() { Base.call(new Object(), 1, 2); }, TypeError);
|
||||
|
||||
class BadSubclass extends Base {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
assertThrows(function() { new BadSubclass(); }, ReferenceError);
|
||||
}());
|
||||
|
||||
(function TestPrototypeWiring() {
|
||||
class Base {
|
||||
constructor(x) {
|
||||
this.foobar = x;
|
||||
}
|
||||
}
|
||||
|
||||
class Subclass extends Base {
|
||||
constructor(x) {
|
||||
super(x);
|
||||
}
|
||||
}
|
||||
|
||||
let s = new Subclass(1);
|
||||
assertSame(1, s.foobar);
|
||||
assertSame(Subclass.prototype, s.__proto__);
|
||||
|
||||
let s1 = new Subclass(1, 2);
|
||||
assertSame(1, s1.foobar);
|
||||
assertTrue(s1.__proto__ === Subclass.prototype);
|
||||
|
||||
let s2 = new Subclass();
|
||||
assertSame(undefined, s2.foobar);
|
||||
assertSame(Subclass.prototype, s2.__proto__);
|
||||
assertThrows(function() { Subclass(1); }, TypeError);
|
||||
assertThrows(function() { Subclass(1,2,3,4); }, TypeError);
|
||||
|
||||
class Subclass2 extends Subclass {
|
||||
constructor() {
|
||||
super(5, 6, 7);
|
||||
}
|
||||
}
|
||||
|
||||
let ss2 = new Subclass2();
|
||||
assertSame(5, ss2.foobar);
|
||||
assertSame(Subclass2.prototype, ss2.__proto__);
|
||||
|
||||
class Subclass3 extends Base {
|
||||
constructor(x,y) {
|
||||
super(x + y);
|
||||
}
|
||||
}
|
||||
|
||||
let ss3 = new Subclass3(27,42-27);
|
||||
assertSame(42, ss3.foobar);
|
||||
assertSame(Subclass3.prototype, ss3.__proto__);
|
||||
}());
|
||||
|
||||
(function TestSublclassingBuiltins() {
|
||||
class ExtendedUint8Array extends Uint8Array {
|
||||
constructor() {
|
||||
super(10);
|
||||
this[0] = 255;
|
||||
this[1] = 0xFFA;
|
||||
}
|
||||
}
|
||||
|
||||
var eua = new ExtendedUint8Array();
|
||||
assertEquals(10, eua.length);
|
||||
assertEquals(10, eua.byteLength);
|
||||
assertEquals(0xFF, eua[0]);
|
||||
assertEquals(0xFA, eua[1]);
|
||||
assertTrue(eua.__proto__ === ExtendedUint8Array.prototype);
|
||||
assertEquals("[object Uint8Array]", Object.prototype.toString.call(eua));
|
||||
}());
|
||||
|
||||
(function TestSubclassingNull() {
|
||||
let N = null;
|
||||
|
||||
class Foo extends N {
|
||||
constructor(x,y) {
|
||||
assertSame(1, x);
|
||||
assertSame(2, y);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
new Foo(1,2);
|
||||
}());
|
||||
|
||||
(function TestSubclassBinding() {
|
||||
class Base {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
let obj = {};
|
||||
class Subclass extends Base {
|
||||
constructor(x,y) {
|
||||
super(x,y);
|
||||
assertTrue(this !== obj);
|
||||
}
|
||||
}
|
||||
|
||||
let f = Subclass.bind(obj);
|
||||
assertThrows(function () { f(1, 2); }, TypeError);
|
||||
let s = new f(1, 2);
|
||||
assertSame(1, s.x);
|
||||
assertSame(2, s.y);
|
||||
assertSame(Subclass.prototype, s.__proto__);
|
||||
|
||||
let s1 = new f(1);
|
||||
assertSame(1, s1.x);
|
||||
assertSame(undefined, s1.y);
|
||||
assertSame(Subclass.prototype, s1.__proto__);
|
||||
|
||||
let g = Subclass.bind(obj, 1);
|
||||
assertThrows(function () { g(8); }, TypeError);
|
||||
let s2 = new g(8);
|
||||
assertSame(1, s2.x);
|
||||
assertSame(8, s2.y);
|
||||
assertSame(Subclass.prototype, s.__proto__);
|
||||
}());
|
||||
assertThrows(function() { Subclass.call(new Object(), 1, 2); }, TypeError);
|
||||
assertThrows(function() { Base.call(new Object(), 1, 2); }, TypeError);
|
||||
|
Loading…
Reference in New Issue
Block a user