new classes: implement default constructors.
R=arv@chromium.org,rossberg@chromium.org BUG=v8:3834 LOG=N Review URL: https://codereview.chromium.org/917753002 Cr-Commit-Position: refs/heads/master@{#26594}
This commit is contained in:
parent
65b10efea1
commit
9b158fa79a
@ -3066,8 +3066,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
|
||||
DCHECK(super_ref != NULL);
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor() {
|
||||
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ Push(r0);
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
@ -3193,9 +3192,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
if (FLAG_experimental_classes) {
|
||||
EmitSuperConstructorCall(expr);
|
||||
} else {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
@ -3268,10 +3267,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
Variable* this_var = super_ref->this_var()->var();
|
||||
|
||||
GetVar(r0, this_var);
|
||||
@ -4177,6 +4176,60 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor_frame, args_set_up, runtime;
|
||||
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ b(eq, &adaptor_frame);
|
||||
// default constructor has no arguments, so no adaptor frame means no args.
|
||||
__ mov(r0, Operand::Zero());
|
||||
__ b(&args_set_up);
|
||||
|
||||
// Copy arguments from adaptor frame.
|
||||
{
|
||||
__ bind(&adaptor_frame);
|
||||
__ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ SmiUntag(r1, r1);
|
||||
|
||||
// Subtract 1 from arguments count, for new.target.
|
||||
__ sub(r1, r1, Operand(1));
|
||||
__ mov(r0, r1);
|
||||
|
||||
// Get arguments pointer in r2.
|
||||
__ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
|
||||
__ add(r2, r2, Operand(StandardFrameConstants::kCallerSPOffset));
|
||||
Label loop;
|
||||
__ bind(&loop);
|
||||
// Pre-decrement r2 with kPointerSize on each iteration.
|
||||
// Pre-decrement in order to skip receiver.
|
||||
__ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex));
|
||||
__ Push(r3);
|
||||
__ sub(r1, r1, Operand(1));
|
||||
__ cmp(r1, Operand::Zero());
|
||||
__ b(ne, &loop);
|
||||
}
|
||||
|
||||
__ bind(&args_set_up);
|
||||
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
|
||||
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
context()->Plug(result_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
|
||||
RegExpConstructResultStub stub(isolate());
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -2754,8 +2754,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
|
||||
DCHECK(super_ref != NULL);
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor() {
|
||||
__ ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ Push(x0);
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
@ -2883,7 +2882,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitSuperConstructorCall(expr);
|
||||
} else {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
@ -2958,7 +2957,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ push(result_register());
|
||||
|
||||
Variable* this_var = super_ref->this_var()->var();
|
||||
@ -3884,6 +3883,60 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor_frame, args_set_up, runtime;
|
||||
Register caller_fp = x11;
|
||||
__ Ldr(x11, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ Ldr(x12, MemOperand(x11, StandardFrameConstants::kContextOffset));
|
||||
__ Cmp(x12, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||
__ B(eq, &adaptor_frame);
|
||||
// default constructor has no arguments, so no adaptor frame means no args.
|
||||
__ Mov(x0, Operand(0));
|
||||
__ B(&args_set_up);
|
||||
|
||||
// Copy arguments from adaptor frame.
|
||||
{
|
||||
__ bind(&adaptor_frame);
|
||||
__ Ldr(x1, MemOperand(x11, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ SmiUntag(x1, x1);
|
||||
|
||||
// Subtract 1 from arguments count, for new.target.
|
||||
__ Sub(x1, x1, Operand(1));
|
||||
__ Mov(x0, x1);
|
||||
|
||||
// Get arguments pointer in x11.
|
||||
__ Add(x11, x11, Operand(x1, LSL, kPointerSizeLog2));
|
||||
__ Add(x11, x11, StandardFrameConstants::kCallerSPOffset);
|
||||
Label loop;
|
||||
__ bind(&loop);
|
||||
// Pre-decrement x11 with kPointerSize on each iteration.
|
||||
// Pre-decrement in order to skip receiver.
|
||||
__ Ldr(x10, MemOperand(x11, -kPointerSize, PreIndex));
|
||||
__ Push(x10);
|
||||
__ Sub(x1, x1, Operand(1));
|
||||
__ Cbnz(x1, &loop);
|
||||
}
|
||||
|
||||
__ bind(&args_set_up);
|
||||
__ Peek(x1, Operand(x0, LSL, kPointerSizeLog2));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
|
||||
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
context()->Plug(result_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
|
||||
RegExpConstructResultStub stub(isolate());
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -647,7 +647,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// |offset| is the offset in the stack where the home object can be found.
|
||||
void EmitSetHomeObjectIfNeeded(Expression* initializer, int offset);
|
||||
|
||||
void EmitLoadSuperConstructor(SuperReference* expr);
|
||||
void EmitLoadSuperConstructor();
|
||||
|
||||
void CallIC(Handle<Code> code,
|
||||
TypeFeedbackId id = TypeFeedbackId::None());
|
||||
|
@ -823,7 +823,9 @@ enum FunctionKind {
|
||||
kAccessorFunction = 1 << 3,
|
||||
kDefaultConstructor = 1 << 4,
|
||||
kSubclassConstructor = 1 << 5,
|
||||
kBaseConstructor = 1 << 6
|
||||
kBaseConstructor = 1 << 6,
|
||||
kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
|
||||
kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor,
|
||||
};
|
||||
|
||||
|
||||
@ -834,7 +836,8 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
|
||||
kind == FunctionKind::kConciseMethod ||
|
||||
kind == FunctionKind::kConciseGeneratorMethod ||
|
||||
kind == FunctionKind::kAccessorFunction ||
|
||||
kind == FunctionKind::kDefaultConstructor ||
|
||||
kind == FunctionKind::kDefaultBaseConstructor ||
|
||||
kind == FunctionKind::kDefaultSubclassConstructor ||
|
||||
kind == FunctionKind::kBaseConstructor ||
|
||||
kind == FunctionKind::kSubclassConstructor;
|
||||
}
|
||||
|
@ -12109,6 +12109,12 @@ void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateDefaultConstructorCallSuper(
|
||||
CallRuntime* call) {
|
||||
return Bailout(kSuperReference);
|
||||
}
|
||||
|
||||
|
||||
// Fast call to math functions.
|
||||
void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
|
||||
DCHECK_EQ(2, call->arguments()->length());
|
||||
|
@ -2956,8 +2956,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
|
||||
DCHECK(super_ref != NULL);
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor() {
|
||||
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
}
|
||||
@ -3075,7 +3074,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
EmitSuperConstructorCall(expr);
|
||||
} else {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ push(result_register());
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
@ -3148,7 +3147,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
__ push(eax);
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ push(result_register());
|
||||
|
||||
Variable* this_var = super_ref->this_var()->var();
|
||||
@ -4071,6 +4070,55 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(eax, new_target_var);
|
||||
__ push(eax);
|
||||
|
||||
EmitLoadSuperConstructor();
|
||||
__ push(result_register());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor_frame, args_set_up, runtime;
|
||||
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ j(equal, &adaptor_frame);
|
||||
// default constructor has no arguments, so no adaptor frame means no args.
|
||||
__ mov(eax, Immediate(0));
|
||||
__ jmp(&args_set_up);
|
||||
|
||||
// Copy arguments from adaptor frame.
|
||||
{
|
||||
__ bind(&adaptor_frame);
|
||||
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ SmiUntag(ecx);
|
||||
|
||||
// Subtract 1 from arguments count, for new.target.
|
||||
__ sub(ecx, Immediate(1));
|
||||
__ mov(eax, ecx);
|
||||
__ lea(edx, Operand(edx, ecx, times_pointer_size,
|
||||
StandardFrameConstants::kCallerSPOffset));
|
||||
Label loop;
|
||||
__ bind(&loop);
|
||||
__ push(Operand(edx, -1 * kPointerSize));
|
||||
__ sub(edx, Immediate(kPointerSize));
|
||||
__ dec(ecx);
|
||||
__ j(not_zero, &loop);
|
||||
}
|
||||
|
||||
__ bind(&args_set_up);
|
||||
__ mov(edi, Operand(esp, eax, times_pointer_size, 0));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
|
||||
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
|
||||
// Load the arguments on the stack and call the stub.
|
||||
RegExpConstructResultStub stub(isolate());
|
||||
|
@ -271,8 +271,11 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
|
||||
int parameter_count = 0;
|
||||
const AstRawString* name = ast_value_factory()->empty_string();
|
||||
|
||||
Scope* function_scope =
|
||||
NewScope(scope, FUNCTION_SCOPE, FunctionKind::kDefaultConstructor);
|
||||
|
||||
FunctionKind kind = call_super && !FLAG_experimental_classes
|
||||
? FunctionKind::kDefaultBaseConstructor
|
||||
: FunctionKind::kDefaultSubclassConstructor;
|
||||
Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind);
|
||||
function_scope->SetLanguageMode(
|
||||
static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT));
|
||||
// Set start and end position to the same value
|
||||
@ -283,17 +286,26 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
|
||||
{
|
||||
AstNodeFactory function_factory(ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope,
|
||||
kDefaultConstructor, &function_factory);
|
||||
kind, &function_factory);
|
||||
|
||||
body = new (zone()) ZoneList<Statement*>(1, zone());
|
||||
body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone());
|
||||
AddAssertIsConstruct(body, pos);
|
||||
if (call_super) {
|
||||
ZoneList<Expression*>* args =
|
||||
new (zone()) ZoneList<Expression*>(0, zone());
|
||||
CallRuntime* call = factory()->NewCallRuntime(
|
||||
ast_value_factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args,
|
||||
pos);
|
||||
body->Add(factory()->NewExpressionStatement(call, pos), zone());
|
||||
if (FLAG_experimental_classes) {
|
||||
CallRuntime* call = factory()->NewCallRuntime(
|
||||
ast_value_factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kInlineDefaultConstructorCallSuper),
|
||||
args, pos);
|
||||
body->Add(factory()->NewReturnStatement(call, pos), zone());
|
||||
} else {
|
||||
CallRuntime* call = factory()->NewCallRuntime(
|
||||
ast_value_factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args,
|
||||
pos);
|
||||
body->Add(factory()->NewExpressionStatement(call, pos), zone());
|
||||
}
|
||||
function_scope->RecordSuperConstructorCallUsage();
|
||||
}
|
||||
|
||||
@ -307,8 +319,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
|
||||
materialized_literal_count, expected_property_count, handler_count,
|
||||
parameter_count, FunctionLiteral::kNoDuplicateParameters,
|
||||
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction,
|
||||
FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor,
|
||||
pos);
|
||||
FunctionLiteral::kNotParenthesized, kind, pos);
|
||||
|
||||
return function_literal;
|
||||
}
|
||||
@ -3894,6 +3905,26 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
|
||||
}
|
||||
|
||||
|
||||
void Parser::AddAssertIsConstruct(ZoneList<Statement*>* body, int pos) {
|
||||
if (!FLAG_experimental_classes) return;
|
||||
|
||||
ZoneList<Expression*>* arguments =
|
||||
new (zone()) ZoneList<Expression*>(0, zone());
|
||||
CallRuntime* construct_check = factory()->NewCallRuntime(
|
||||
ast_value_factory()->is_construct_call_string(),
|
||||
Runtime::FunctionForId(Runtime::kInlineIsConstructCall), arguments, pos);
|
||||
CallRuntime* non_callable_error = factory()->NewCallRuntime(
|
||||
ast_value_factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kThrowConstructorNonCallableError),
|
||||
arguments, pos);
|
||||
IfStatement* if_statement = factory()->NewIfStatement(
|
||||
factory()->NewUnaryOperation(Token::NOT, construct_check, pos),
|
||||
factory()->NewReturnStatement(non_callable_error, pos),
|
||||
factory()->NewEmptyStatement(pos), pos);
|
||||
body->Add(if_statement, zone());
|
||||
}
|
||||
|
||||
|
||||
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
const AstRawString* function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
|
||||
@ -3916,22 +3947,8 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
|
||||
// For concise constructors, check that they are constructed,
|
||||
// not called.
|
||||
if (FLAG_experimental_classes && i::IsConstructor(kind)) {
|
||||
ZoneList<Expression*>* arguments =
|
||||
new (zone()) ZoneList<Expression*>(0, zone());
|
||||
CallRuntime* construct_check = factory()->NewCallRuntime(
|
||||
ast_value_factory()->is_construct_call_string(),
|
||||
Runtime::FunctionForId(Runtime::kInlineIsConstructCall), arguments,
|
||||
pos);
|
||||
CallRuntime* non_callable_error = factory()->NewCallRuntime(
|
||||
ast_value_factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kThrowConstructorNonCallableError),
|
||||
arguments, pos);
|
||||
IfStatement* if_statement = factory()->NewIfStatement(
|
||||
factory()->NewUnaryOperation(Token::NOT, construct_check, pos),
|
||||
factory()->NewReturnStatement(non_callable_error, pos),
|
||||
factory()->NewEmptyStatement(pos), pos);
|
||||
body->Add(if_statement, zone());
|
||||
if (i::IsConstructor(kind)) {
|
||||
AddAssertIsConstruct(body, pos);
|
||||
}
|
||||
|
||||
// For generators, allocate and yield an iterator on function entry.
|
||||
|
@ -840,6 +840,8 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
|
||||
IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
|
||||
|
||||
void AddAssertIsConstruct(ZoneList<Statement*>* body, int pos);
|
||||
|
||||
// Factory methods.
|
||||
FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
|
||||
int end_pos);
|
||||
|
@ -414,7 +414,15 @@ RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(RuntimeReference_DefaultConstructorCallSuper) {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// TODO(dslomov): deprecated, will remove when experimenal classes is default.
|
||||
RUNTIME_FUNCTION(Runtime_DefaultConstructorSuperCall) {
|
||||
CHECK(!FLAG_experimental_classes);
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
|
||||
|
@ -654,6 +654,7 @@ namespace internal {
|
||||
F(IsJSProxy, 1, 1) \
|
||||
F(IsConstructCall, 0, 1) \
|
||||
F(CallFunction, -1 /* receiver + n args + function */, 1) \
|
||||
F(DefaultConstructorCallSuper, 0, 1) \
|
||||
F(ArgumentsLength, 0, 1) \
|
||||
F(Arguments, 1, 1) \
|
||||
F(ValueOf, 1, 1) \
|
||||
|
@ -936,7 +936,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
|
||||
if (has_new_target()) {
|
||||
// Subtract 1 from smi-tagged arguments count.
|
||||
__ SmiToInteger32(rcx, rcx);
|
||||
__ decp(rcx);
|
||||
__ decl(rcx);
|
||||
__ Integer32ToSmi(rcx, rcx);
|
||||
}
|
||||
__ movp(args.GetArgumentOperand(2), rcx);
|
||||
|
@ -2962,8 +2962,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
|
||||
DCHECK(super_ref != NULL);
|
||||
void FullCodeGenerator::EmitLoadSuperConstructor() {
|
||||
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ CallRuntime(Runtime::kGetPrototype, 1);
|
||||
}
|
||||
@ -3080,9 +3079,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
if (FLAG_experimental_classes) {
|
||||
EmitSuperConstructorCall(expr);
|
||||
} else {
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
SuperReference* super_ref = callee->AsSuperReference();
|
||||
VisitForStackValue(super_ref->this_var());
|
||||
EmitCall(expr, CallICState::METHOD);
|
||||
}
|
||||
@ -3153,10 +3152,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
EmitLoadSuperConstructor(super_ref);
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
|
||||
SuperReference* super_ref = expr->expression()->AsSuperReference();
|
||||
Variable* this_var = super_ref->this_var()->var();
|
||||
|
||||
GetVar(rax, this_var);
|
||||
@ -4071,6 +4070,55 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
|
||||
Variable* new_target_var = scope()->DeclarationScope()->new_target_var();
|
||||
GetVar(result_register(), new_target_var);
|
||||
__ Push(result_register());
|
||||
|
||||
EmitLoadSuperConstructor();
|
||||
__ Push(result_register());
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor_frame, args_set_up, runtime;
|
||||
__ movp(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ movp(rcx, Operand(rdx, StandardFrameConstants::kContextOffset));
|
||||
__ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||
__ j(equal, &adaptor_frame);
|
||||
// default constructor has no arguments, so no adaptor frame means no args.
|
||||
__ movp(rax, Immediate(0));
|
||||
__ jmp(&args_set_up);
|
||||
|
||||
// Copy arguments from adaptor frame.
|
||||
{
|
||||
__ bind(&adaptor_frame);
|
||||
__ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ SmiToInteger64(rcx, rcx);
|
||||
|
||||
// Subtract 1 from arguments count, for new.target.
|
||||
__ subp(rcx, Immediate(1));
|
||||
__ movp(rax, rcx);
|
||||
__ leap(rdx, Operand(rdx, rcx, times_pointer_size,
|
||||
StandardFrameConstants::kCallerSPOffset));
|
||||
Label loop;
|
||||
__ bind(&loop);
|
||||
__ Push(Operand(rdx, -1 * kPointerSize));
|
||||
__ subp(rdx, Immediate(kPointerSize));
|
||||
__ decp(rcx);
|
||||
__ j(not_zero, &loop);
|
||||
}
|
||||
|
||||
__ bind(&args_set_up);
|
||||
__ movp(rdi, Operand(rsp, rax, times_pointer_size, 0));
|
||||
|
||||
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
|
||||
__ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
||||
|
||||
__ Drop(1);
|
||||
|
||||
context()->Plug(result_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
|
||||
RegExpConstructResultStub stub(isolate());
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -172,7 +172,7 @@
|
||||
assertEquals(10, eua.byteLength);
|
||||
assertEquals(0xFF, eua[0]);
|
||||
assertEquals(0xFA, eua[1]);
|
||||
assertTrue(eua.__proto__ === ExtendedUint8Array.prototype);
|
||||
assertSame(ExtendedUint8Array.prototype, eua.__proto__);
|
||||
assertEquals("[object Uint8Array]", Object.prototype.toString.call(eua));
|
||||
}());
|
||||
|
||||
@ -225,3 +225,61 @@
|
||||
assertSame(8, s2.y);
|
||||
assertSame(Subclass.prototype, s.__proto__);
|
||||
}());
|
||||
|
||||
|
||||
(function TestDefaultConstructor() {
|
||||
class Base1 { }
|
||||
assertThrows(function() { Base1(); }, TypeError);
|
||||
|
||||
class Subclass1 extends Base1 { }
|
||||
|
||||
assertThrows(function() { Subclass1(); }, TypeError);
|
||||
|
||||
let s1 = new Subclass1();
|
||||
assertSame(s1.__proto__, Subclass1.prototype);
|
||||
|
||||
class Base2 {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
class Subclass2 extends Base2 {};
|
||||
|
||||
let s2 = new Subclass2(1, 2);
|
||||
|
||||
assertSame(s2.__proto__, Subclass2.prototype);
|
||||
assertSame(1, s2.x);
|
||||
assertSame(2, s2.y);
|
||||
|
||||
let f = Subclass2.bind({}, 3, 4);
|
||||
let s2prime = new f();
|
||||
assertSame(s2prime.__proto__, Subclass2.prototype);
|
||||
assertSame(3, s2prime.x);
|
||||
assertSame(4, s2prime.y);
|
||||
|
||||
let obj = {};
|
||||
class Base3 {
|
||||
constructor() {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class Subclass3 extends Base3 {};
|
||||
|
||||
let s3 = new Subclass3();
|
||||
assertSame(obj, s3);
|
||||
|
||||
class ExtendedUint8Array extends Uint8Array { }
|
||||
|
||||
var eua = new ExtendedUint8Array(10);
|
||||
assertEquals(10, eua.length);
|
||||
assertEquals(10, eua.byteLength);
|
||||
eua[0] = 0xFF;
|
||||
eua[1] = 0xFFA;
|
||||
assertEquals(0xFF, eua[0]);
|
||||
assertEquals(0xFA, eua[1]);
|
||||
assertSame(ExtendedUint8Array.prototype, eua.__proto__);
|
||||
assertEquals("[object Uint8Array]", Object.prototype.toString.call(eua));
|
||||
}());
|
||||
|
Loading…
Reference in New Issue
Block a user