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:
dslomov 2015-02-11 09:22:50 -08:00 committed by Commit bot
parent 65b10efea1
commit 9b158fa79a
13 changed files with 349 additions and 52 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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