[class] Initialize class fields after binding this

Class fields needs to be initialized after `this` is bound, as per the
new spec change:
https://github.com/tc39/proposal-class-fields/pull/92

This CL moves the initialization of `this` from parser desugaring to
the bytecode generator.

Bug: v8:7647
Change-Id: I20f749403e5a4d2f06a39726cf39012ceb541987
Reviewed-on: https://chromium-review.googlesource.com/1014383
Reviewed-by: Mythri Alle <mythria@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52646}
This commit is contained in:
Sathya Gunasekaran 2018-04-16 12:35:57 -07:00 committed by Commit Bot
parent a0a4c71e3f
commit eb4ebf98c9
5 changed files with 47 additions and 31 deletions

View File

@ -3639,6 +3639,16 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
}
}
// Explicit calls to the super constructor using super() perform an
// implicit binding assignment to the 'this' variable.
//
// Default constructors don't need have to do the assignment because
// 'this' isn't accessed in default constructors.
if (!IsDefaultConstructor(info()->literal()->kind())) {
BuildVariableAssignment(super->this_var()->var(), Token::INIT,
HoleCheckMode::kRequired);
}
// The derived constructor has the correct bit set always, so we
// don't emit code to load and call the initializer if not
// required.

View File

@ -3424,24 +3424,12 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
Call::PossiblyEval is_possibly_eval =
CheckPossibleEvalCall(result, scope());
bool is_super_call = result->IsSuperCallReference();
if (spread_pos.IsValid()) {
result = impl()->SpreadCall(result, args, pos, is_possibly_eval);
} else {
result = factory()->NewCall(result, args, pos, is_possibly_eval);
}
// Explicit calls to the super constructor using super() perform an
// implicit binding assignment to the 'this' variable.
if (is_super_call) {
classifier()->RecordAssignmentPatternError(
Scanner::Location(pos, scanner()->location().end_pos),
MessageTemplate::kInvalidDestructuringTarget);
ExpressionT this_expr = impl()->ThisExpression(pos);
result =
factory()->NewAssignment(Token::INIT, this_expr, result, pos);
}
if (fni_ != nullptr) fni_->RemoveLastFunction();
break;
}

View File

@ -104,7 +104,7 @@ snippet: "
test = new B().constructor;
})();
"
frame size: 5
frame size: 6
parameter count: 1
bytecode array length: 40
bytecodes: [
@ -116,14 +116,14 @@ bytecodes: [
B(Star), R(4),
B(Ldar), R(0),
/* 118 E> */ B(Construct), R(3), R(4), U8(1), U8(0),
B(Star), R(2),
B(Star), R(5),
B(Ldar), R(this),
/* 118 E> */ B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(2), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(5), R(this),
/* 128 S> */ B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
B(LdaSmi), I8(2),
/* 136 E> */ B(StaNamedProperty), R(2), U8(0), U8(2),
/* 136 E> */ B(StaNamedProperty), R(this), U8(0), U8(2),
B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
/* 141 S> */ B(Return),
@ -147,7 +147,7 @@ snippet: "
test = new B().constructor;
})();
"
frame size: 4
frame size: 5
parameter count: 1
bytecode array length: 36
bytecodes: [
@ -157,14 +157,14 @@ bytecodes: [
B(GetSuperConstructor), R(3),
B(Ldar), R(0),
/* 117 E> */ B(Construct), R(3), R(0), U8(0), U8(0),
B(Star), R(2),
B(Star), R(4),
B(Ldar), R(this),
/* 117 E> */ B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(2), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(4), R(this),
/* 126 S> */ B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
B(LdaSmi), I8(2),
/* 134 E> */ B(StaNamedProperty), R(2), U8(0), U8(2),
/* 134 E> */ B(StaNamedProperty), R(this), U8(0), U8(2),
B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
/* 139 S> */ B(Return),

View File

@ -49,7 +49,7 @@ snippet: "
test = new B(1, 2, 3).constructor;
})();
"
frame size: 8
frame size: 9
parameter count: 1
bytecode array length: 40
bytecodes: [
@ -65,10 +65,10 @@ bytecodes: [
B(Ldar), R(0),
B(Mov), R(2), R(7),
/* 140 E> */ B(ConstructWithSpread), R(5), R(6), U8(2), U8(0),
B(Star), R(4),
B(Star), R(8),
B(Ldar), R(this),
/* 140 E> */ B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(4), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(8), R(this),
B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
/* 159 S> */ B(Return),
@ -142,10 +142,10 @@ bytecodes: [
B(Mov), R(6), R(9),
B(Mov), R(0), R(10),
/* 140 E> */ B(CallJSRuntime), U8(%reflect_construct), R(8), U8(3),
B(Star), R(4),
B(Star), R(11),
B(Ldar), R(this),
/* 140 E> */ B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(4), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(11), R(this),
B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
/* 162 S> */ B(Return),

View File

@ -507,7 +507,7 @@ x()();
}
assertThrows(() => new C1, ReferenceError);
assertEquals([1,1], log);
assertEquals([1], log);
log = [];
class C2 extends class {} {
@ -520,7 +520,7 @@ x()();
}
assertThrows(() => new C2, ReferenceError);
assertEquals([1,1], log);
assertEquals([1], log);
}
{
@ -696,3 +696,21 @@ x()();
let x = new X;
assertEquals(1, x.p);
}
{
let thisInInitializer, thisInConstructor, thisFromArrowFn, arrowFn;
let C = class extends class {} {
field = (thisInInitializer = this, thisFromArrowFn = arrowFn());
constructor() {
arrowFn = () => this;
super();
thisInConstructor = this;
}
};
let c = new C();
assertSame(thisInInitializer, c);
assertSame(thisFromArrowFn, c);
assertSame(thisInConstructor, c);
}