diff --git a/include/hermes/IR/IR.h b/include/hermes/IR/IR.h index a85815c075f..dddfe2d7bbf 100644 --- a/include/hermes/IR/IR.h +++ b/include/hermes/IR/IR.h @@ -1773,7 +1773,8 @@ class Function : public llvh::ilist_node_with_parent, enum class DefinitionKind { ES5Function, - ES6Constructor, + ES6BaseConstructor, + ES6DerivedConstructor, ES6Arrow, ES6Method, // This corresponds to the synthetic function we create in IRGen, which is diff --git a/lib/IR/IR.cpp b/lib/IR/IR.cpp index cf58449badd..eb2da0e969d 100644 --- a/lib/IR/IR.cpp +++ b/lib/IR/IR.cpp @@ -162,7 +162,8 @@ static Type functionNewTargetType(Function::DefinitionKind defKind) { switch (defKind) { case Function::DefinitionKind::ES5Function: return Type::unionTy(Type::createObject(), Type::createUndefined()); - case Function::DefinitionKind::ES6Constructor: + case Function::DefinitionKind::ES6BaseConstructor: + case Function::DefinitionKind::ES6DerivedConstructor: return Type::createObject(); case Function::DefinitionKind::ES6Arrow: case Function::DefinitionKind::GeneratorInnerArrow: @@ -229,8 +230,10 @@ std::string Function::getDefinitionKindStr(bool isDescriptive) const { switch (definitionKind_) { case Function::DefinitionKind::ES5Function: return "function"; - case Function::DefinitionKind::ES6Constructor: - return "constructor"; + case Function::DefinitionKind::ES6BaseConstructor: + return "base constructor"; + case Function::DefinitionKind::ES6DerivedConstructor: + return "derived constructor"; case Function::DefinitionKind::ES6Arrow: return isDescriptive ? "arrow function" : "arrow"; case Function::DefinitionKind::ES6Method: @@ -283,7 +286,8 @@ llvh::Optional Function::getSourceRepresentationStr() const { Function::ProhibitInvoke Function::getProhibitInvoke() const { // ES6 constructors must be invoked as constructors. - if (definitionKind_ == DefinitionKind::ES6Constructor) + if (definitionKind_ == DefinitionKind::ES6BaseConstructor || + definitionKind_ == DefinitionKind::ES6DerivedConstructor) return ProhibitInvoke::ProhibitCall; // Generators, async functions, methods, and arrow functions may not be diff --git a/lib/IR/IRVerifier.cpp b/lib/IR/IRVerifier.cpp index 5ed018ae109..10818cebca9 100644 --- a/lib/IR/IRVerifier.cpp +++ b/lib/IR/IRVerifier.cpp @@ -1481,7 +1481,8 @@ bool Verifier::visitGetNewTargetInst(GetNewTargetInst const &Inst) { AssertIWithMsg( Inst, definitionKind == Function::DefinitionKind::ES5Function || - definitionKind == Function::DefinitionKind::ES6Constructor || + definitionKind == Function::DefinitionKind::ES6BaseConstructor || + definitionKind == Function::DefinitionKind::ES6DerivedConstructor || definitionKind == Function::DefinitionKind::ES6Method, "GetNewTargetInst can only be used in ES6 constructors, ES5 functions, and ES6 methods"); AssertIWithMsg( diff --git a/lib/IRGen/ESTreeIRGen-expr.cpp b/lib/IRGen/ESTreeIRGen-expr.cpp index 8663c44a4f8..a8ba742a5c3 100644 --- a/lib/IRGen/ESTreeIRGen-expr.cpp +++ b/lib/IRGen/ESTreeIRGen-expr.cpp @@ -2476,7 +2476,8 @@ Value *ESTreeIRGen::genNewTarget() { switch (curFunction()->function->getDefinitionKind()) { case Function::DefinitionKind::ES5Function: - case Function::DefinitionKind::ES6Constructor: + case Function::DefinitionKind::ES6BaseConstructor: + case Function::DefinitionKind::ES6DerivedConstructor: value = Builder.createGetNewTargetInst( curFunction()->function->getNewTargetParam()); break; diff --git a/lib/IRGen/ESTreeIRGen-func.cpp b/lib/IRGen/ESTreeIRGen-func.cpp index fdd850d5e9b..3bcf6c767a9 100644 --- a/lib/IRGen/ESTreeIRGen-func.cpp +++ b/lib/IRGen/ESTreeIRGen-func.cpp @@ -403,33 +403,33 @@ NormalFunction *ESTreeIRGen::genBasicFunction( parentScope); } - if (functionKind == Function::DefinitionKind::ES6Constructor) { - if (curFunction()->hasLegacyClassContext()) { - if (curFunction()->getSemInfo()->constructorKind == - sema::FunctionInfo::ConstructorKind::Derived) { - // Initialize the 'checked this' in derived class constructors. - newFunctionContext.capturedState.thisVal = Builder.createVariable( - curFunction()->curScope->getVariableScope(), - Builder.createIdentifier("?CHECKED_this"), - Type::unionTy(Type::createObject(), Type::createEmpty()), - true); - Builder.createStoreFrameInst( - curFunction()->curScope, - Builder.getLiteralEmpty(), - newFunctionContext.capturedState.thisVal); - } else { - // We generate this call after calling super for derived classes. - emitLegacyInstanceElementsInitCall(); - } - } else { + if (curFunction()->hasLegacyClassContext()) { + if (functionKind == Function::DefinitionKind::ES6BaseConstructor) { + // We only need to generate this here for base classes. It's not + // required for derived because they generate this call after calling + // super(). + emitLegacyInstanceElementsInitCall(); + } else if ( + functionKind == Function::DefinitionKind::ES6DerivedConstructor) { + // Initialize the 'checked this' in derived class constructors. + newFunctionContext.capturedState.thisVal = Builder.createVariable( + curFunction()->curScope->getVariableScope(), + Builder.createIdentifier("?CHECKED_this"), + Type::unionTy(Type::createObject(), Type::createEmpty()), + true); + Builder.createStoreFrameInst( + curFunction()->curScope, + Builder.getLiteralEmpty(), + newFunctionContext.capturedState.thisVal); + } + } else { + if (functionKind == Function::DefinitionKind::ES6BaseConstructor) { assert( curFunction()->hasTypedClassContext() && "ES6Constructor has no valid class context"); - // If we're compiling a typed constructor with no superclass, emit the - // field inits at the start. - if (superClassNode == nullptr) { - emitTypedFieldInitCall(typedClassContext.type); - } + // If we're compiling a typed base class constructor, emit the field + // inits at the start. + emitTypedFieldInitCall(typedClassContext.type); } } @@ -701,10 +701,8 @@ void ESTreeIRGen::initCaptureStateInES5FunctionHelper() { // `this` is managed separately in the case of a legacy derived class // constructor. if (!(curFunction()->function->getDefinitionKind() == - Function::DefinitionKind::ES6Constructor && - curFunction()->hasLegacyClassContext() && - semCtx_.nearestNonArrow(curFunction()->getSemInfo())->constructorKind == - sema::FunctionInfo::ConstructorKind::Derived)) { + Function::DefinitionKind::ES6DerivedConstructor && + curFunction()->hasLegacyClassContext())) { auto *th = Builder.createVariable( scope, genAnonymousLabelName("this"), diff --git a/lib/IRGen/ESTreeIRGen-legacy-class.cpp b/lib/IRGen/ESTreeIRGen-legacy-class.cpp index 72c52f8cb80..880cccd433e 100644 --- a/lib/IRGen/ESTreeIRGen-legacy-class.cpp +++ b/lib/IRGen/ESTreeIRGen-legacy-class.cpp @@ -112,7 +112,8 @@ CreateClassInst *ESTreeIRGen::genLegacyClassLike( llvh::cast(consMethodNode->_value), curScope->getVariableScope(), superClassNode, - Function::DefinitionKind::ES6Constructor, + superClassNode ? Function::DefinitionKind::ES6DerivedConstructor + : Function::DefinitionKind::ES6BaseConstructor, clsPrototypeVar, consMethodNode); } @@ -385,7 +386,9 @@ NormalFunction *ESTreeIRGen::genLegacyImplicitConstructor( auto *consFunc = Builder.createFunction( className, - Function::DefinitionKind::ES6Constructor, + funcInfo->constructorKind == sema::FunctionInfo::ConstructorKind::Derived + ? Function::DefinitionKind::ES6DerivedConstructor + : Function::DefinitionKind::ES6BaseConstructor, /* strictMode */ true, funcInfo->customDirectives); diff --git a/lib/IRGen/ESTreeIRGen-typed-class.cpp b/lib/IRGen/ESTreeIRGen-typed-class.cpp index 5e7f6b20c5b..32ffcb81458 100644 --- a/lib/IRGen/ESTreeIRGen-typed-class.cpp +++ b/lib/IRGen/ESTreeIRGen-typed-class.cpp @@ -99,7 +99,8 @@ void ESTreeIRGen::genClassDeclaration(ESTree::ClassDeclarationNode *node) { llvh::cast(consMethod->_value), consName, node->_superClass, - Function::DefinitionKind::ES6Constructor); + node->_superClass ? Function::DefinitionKind::ES6DerivedConstructor + : Function::DefinitionKind::ES6BaseConstructor); } else { // The constructor is implicit. consFunction = genTypedImplicitConstructor(consName, superClass); diff --git a/test/IRGen/flow/class-constructor-super.js b/test/IRGen/flow/class-constructor-super.js index a922e33cd2d..ae2778c8b81 100644 --- a/test/IRGen/flow/class-constructor-super.js +++ b/test/IRGen/flow/class-constructor-super.js @@ -73,7 +73,7 @@ new D(); // CHECK:scope %VS2 [] -// CHECK:constructor C(): any [typed] +// CHECK:base constructor C(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment // CHECK-NEXT: %1 = CreateScopeInst (:environment) %VS2: any, %0: environment @@ -82,7 +82,7 @@ new D(); // CHECK:scope %VS3 [] -// CHECK:constructor D(): any [typed] +// CHECK:derived constructor D(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/IRGen/flow/class-method-inherited.js b/test/IRGen/flow/class-method-inherited.js index 9f2903b9ecb..2503e7369e0 100644 --- a/test/IRGen/flow/class-method-inherited.js +++ b/test/IRGen/flow/class-method-inherited.js @@ -99,7 +99,7 @@ new D().inherited(); // CHECK:scope %VS4 [] -// CHECK:constructor D(): any [typed] +// CHECK:derived constructor D(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/IRGen/flow/class-method-override.js b/test/IRGen/flow/class-method-override.js index 854992b6661..935570d9b0b 100644 --- a/test/IRGen/flow/class-method-override.js +++ b/test/IRGen/flow/class-method-override.js @@ -142,7 +142,7 @@ function foo(c: C, d: D){ // CHECK:scope %VS6 [] -// CHECK:constructor D(): any [typed] +// CHECK:derived constructor D(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/IRGen/flow/class-super-method.js b/test/IRGen/flow/class-super-method.js index 4b94f9d63ed..15c61a01014 100644 --- a/test/IRGen/flow/class-super-method.js +++ b/test/IRGen/flow/class-super-method.js @@ -79,7 +79,7 @@ class B extends A { // CHECK:scope %VS2 [x: any] -// CHECK:constructor A(x: number): any [typed] +// CHECK:base constructor A(x: number): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment @@ -107,7 +107,7 @@ class B extends A { // CHECK:scope %VS4 [x: any] -// CHECK:constructor B(x: number): any [typed] +// CHECK:derived constructor B(x: number): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/IRGen/flow/class-super-prop.js b/test/IRGen/flow/class-super-prop.js index 4e162b99986..611b1716d12 100644 --- a/test/IRGen/flow/class-super-prop.js +++ b/test/IRGen/flow/class-super-prop.js @@ -74,7 +74,7 @@ class B extends A { // CHECK:scope %VS2 [x: any] -// CHECK:constructor A(x: number): any [typed] +// CHECK:base constructor A(x: number): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment @@ -89,7 +89,7 @@ class B extends A { // CHECK:scope %VS3 [x: any] -// CHECK:constructor B(x: number): any [typed] +// CHECK:derived constructor B(x: number): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/IRGen/flow/class1.js b/test/IRGen/flow/class1.js index 55b262f9089..099453d3e56 100644 --- a/test/IRGen/flow/class1.js +++ b/test/IRGen/flow/class1.js @@ -56,7 +56,7 @@ return [dotProduct, Vec2D]; // CHECK-NEXT: ReturnInst %8: number // CHECK-NEXT:function_end -// CHECK:constructor Vec2D(x: number, y: number): undefined [typed] +// CHECK:base constructor Vec2D(x: number, y: number): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = LoadParamInst (:number) %y: number diff --git a/test/IRGen/flow/field-inits.js b/test/IRGen/flow/field-inits.js index 47a35f4934a..1bf9615b846 100644 --- a/test/IRGen/flow/field-inits.js +++ b/test/IRGen/flow/field-inits.js @@ -164,7 +164,7 @@ function f(i: number): number { // CHECK:scope %VS4 [] -// CHECK:constructor A(): any [typed] +// CHECK:base constructor A(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment @@ -194,7 +194,7 @@ function f(i: number): number { // CHECK:scope %VS6 [] -// CHECK:constructor B(): any [typed] +// CHECK:base constructor B(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment @@ -259,7 +259,7 @@ function f(i: number): number { // CHECK:scope %VS11 [] -// CHECK:constructor C1(): any [typed] +// CHECK:derived constructor C1(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment @@ -290,7 +290,7 @@ function f(i: number): number { // CHECK:scope %VS13 [] -// CHECK:constructor "A 1#"(): any [typed] +// CHECK:base constructor "A 1#"(): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS2: any, %parentScope: environment diff --git a/test/IRGen/flow/generic-class-id.js b/test/IRGen/flow/generic-class-id.js index 5a5cbf48975..3aa48eedfb6 100644 --- a/test/IRGen/flow/generic-class-id.js +++ b/test/IRGen/flow/generic-class-id.js @@ -79,7 +79,7 @@ const s: string = i2.val; // CHECK:scope %VS2 [val: any] -// CHECK:constructor ID(val: number): any [typed] +// CHECK:base constructor ID(val: number): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment @@ -94,7 +94,7 @@ const s: string = i2.val; // CHECK:scope %VS3 [val: any] -// CHECK:constructor "ID 1#"(val: string): any [typed] +// CHECK:base constructor "ID 1#"(val: string): any [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/Optimizer/flow/inline-constructor-small.js b/test/Optimizer/flow/inline-constructor-small.js index bfe0e80cc55..e9cd4d2f323 100644 --- a/test/Optimizer/flow/inline-constructor-small.js +++ b/test/Optimizer/flow/inline-constructor-small.js @@ -38,7 +38,7 @@ print(p1.x, p2.x); // CHECK-NEXT: ReturnInst undefined: undefined // CHECK-NEXT:function_end -// CHECK:constructor Point(x: number, y: number): undefined [typed] +// CHECK:base constructor Point(x: number, y: number): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = LoadParamInst (:number) %x: number diff --git a/test/Optimizer/object-with-object-field-alloc.js b/test/Optimizer/object-with-object-field-alloc.js index 642bab9e546..5f8d1476d4e 100644 --- a/test/Optimizer/object-with-object-field-alloc.js +++ b/test/Optimizer/object-with-object-field-alloc.js @@ -51,7 +51,7 @@ new Foo(); // CHECK-NEXT: ReturnInst %12: undefined // CHECK-NEXT:function_end -// CHECK:constructor O(): undefined [typed] +// CHECK:base constructor O(): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = HBCLoadConstInst (:number) 7: number // CHECK-NEXT: %1 = LoadParamInst (:object) %: object @@ -60,7 +60,7 @@ new Foo(); // CHECK-NEXT: ReturnInst %3: undefined // CHECK-NEXT:function_end -// CHECK:constructor Foo(): undefined [typed] +// CHECK:base constructor Foo(): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment diff --git a/test/Optimizer/typed-object-promotion.js b/test/Optimizer/typed-object-promotion.js index 45aadd2500e..58c120c54c4 100644 --- a/test/Optimizer/typed-object-promotion.js +++ b/test/Optimizer/typed-object-promotion.js @@ -38,7 +38,7 @@ print(foo.x, foo.y); // CHECK-NEXT: ReturnInst undefined: undefined // CHECK-NEXT:function_end -// CHECK:constructor Foo(x: number, y: number): undefined [typed] +// CHECK:base constructor Foo(x: number, y: number): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = LoadParamInst (:number) %x: number diff --git a/test/Optimizer/uninit-prop-access-opt.js b/test/Optimizer/uninit-prop-access-opt.js index 154042a956c..127c69febe8 100644 --- a/test/Optimizer/uninit-prop-access-opt.js +++ b/test/Optimizer/uninit-prop-access-opt.js @@ -85,14 +85,14 @@ print(f()); // CHECK-NEXT: ReturnInst undefined: undefined // CHECK-NEXT:function_end -// CHECK:constructor O(): undefined [typed] +// CHECK:base constructor O(): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: PrStoreInst 7: number, %0: object, 0: number, "i": string, true: boolean // CHECK-NEXT: ReturnInst undefined: undefined // CHECK-NEXT:function_end -// CHECK:constructor Foo(): undefined [typed] +// CHECK:base constructor Foo(): undefined [typed] // CHECK-NEXT:%BB0: // CHECK-NEXT: %0 = LoadParamInst (:object) %: object // CHECK-NEXT: %1 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment