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:
dslomov 2015-02-10 17:36:17 -08:00 committed by Commit bot
parent 8aed43e82c
commit 8e4ec9dd13
40 changed files with 145 additions and 504 deletions

View File

@ -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 =

View File

@ -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());

View File

@ -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;

View File

@ -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);

View File

@ -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());

View File

@ -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;

View File

@ -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);

View File

@ -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) \

View File

@ -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);

View File

@ -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);

View File

@ -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(); }

View File

@ -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());

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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
};

View File

@ -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);

View File

@ -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);

View File

@ -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());

View File

@ -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;

View File

@ -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 -

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
}

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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();
}

View File

@ -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.

View File

@ -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.

View File

@ -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());

View File

@ -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;

View File

@ -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);
}

View File

@ -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);