}
-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);
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);
}
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);
}
+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();
}
-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);
EmitSuperConstructorCall(expr);
} else {
SuperReference* super_ref = callee->AsSuperReference();
- EmitLoadSuperConstructor(super_ref);
+ EmitLoadSuperConstructor();
__ Push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
__ Push(result_register());
SuperReference* super_ref = expr->expression()->AsSuperReference();
- EmitLoadSuperConstructor(super_ref);
+ EmitLoadSuperConstructor();
__ push(result_register());
Variable* this_var = super_ref->this_var()->var();
}
+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();
// |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());
kAccessorFunction = 1 << 3,
kDefaultConstructor = 1 << 4,
kSubclassConstructor = 1 << 5,
- kBaseConstructor = 1 << 6
+ kBaseConstructor = 1 << 6,
+ kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
+ kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor,
};
kind == FunctionKind::kConciseMethod ||
kind == FunctionKind::kConciseGeneratorMethod ||
kind == FunctionKind::kAccessorFunction ||
- kind == FunctionKind::kDefaultConstructor ||
+ kind == FunctionKind::kDefaultBaseConstructor ||
+ kind == FunctionKind::kDefaultSubclassConstructor ||
kind == FunctionKind::kBaseConstructor ||
kind == FunctionKind::kSubclassConstructor;
}
}
+void HOptimizedGraphBuilder::GenerateDefaultConstructorCallSuper(
+ CallRuntime* call) {
+ return Bailout(kSuperReference);
+}
+
+
// Fast call to math functions.
void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
DCHECK_EQ(2, call->arguments()->length());
}
-void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
- DCHECK(super_ref != NULL);
+void FullCodeGenerator::EmitLoadSuperConstructor() {
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ CallRuntime(Runtime::kGetPrototype, 1);
}
EmitSuperConstructorCall(expr);
} else {
SuperReference* super_ref = callee->AsSuperReference();
- EmitLoadSuperConstructor(super_ref);
+ EmitLoadSuperConstructor();
__ push(result_register());
VisitForStackValue(super_ref->this_var());
EmitCall(expr, CallICState::METHOD);
__ push(eax);
SuperReference* super_ref = expr->expression()->AsSuperReference();
- EmitLoadSuperConstructor(super_ref);
+ EmitLoadSuperConstructor();
__ push(result_register());
Variable* this_var = super_ref->this_var()->var();
}
+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());
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
{
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();
}
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;
}
}
+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) {
// 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.
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);
}
+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);
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) \
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);
}
-void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
- DCHECK(super_ref != NULL);
+void FullCodeGenerator::EmitLoadSuperConstructor() {
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ CallRuntime(Runtime::kGetPrototype, 1);
}
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);
}
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);
}
+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();
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));
}());
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));
+}());