Skip to content

Commit 15d8b24

Browse files
committed
fix: create 2 kinds of constructor for instantiation and instantiation of inherited types
1 parent 69cc1cb commit 15d8b24

File tree

101 files changed

+8217
-5978
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+8217
-5978
lines changed

src/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ export namespace CommonNames {
166166
export const this_ = "this";
167167
export const super_ = "super";
168168
export const constructor = "constructor";
169+
export const raw_constructor = "raw_constructor";
169170
// constants
170171
export const ASC_TARGET = "ASC_TARGET";
171172
export const ASC_RUNTIME = "ASC_RUNTIME";

src/compiler.ts

Lines changed: 133 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -8764,133 +8764,161 @@ export class Compiler extends DiagnosticEmitter {
87648764
return this.compileInstantiate(ctor, expression.args, constraints, expression);
87658765
}
87668766

8767-
/** Gets the compiled constructor of the specified class or generates one if none is present. */
8768-
ensureConstructor(
8767+
private createConstructorInstance(
8768+
/** true mean this constructor is externally visible, need to handle memory allocation */
8769+
isExternallyVisible: bool,
87698770
/** Class wanting a constructor. */
87708771
classInstance: Class,
87718772
/** Report node. */
87728773
reportNode: Node
87738774
): Function {
8774-
let instance = classInstance.constructorInstance;
8775-
if (instance) {
8776-
// shortcut if already compiled
8777-
if (instance.is(CommonFlags.Compiled)) return instance;
8778-
// do not attempt to compile if inlined anyway
8779-
if (!instance.hasDecorator(DecoratorFlags.Inline)) this.compileFunction(instance);
8775+
const name = isExternallyVisible ? CommonNames.constructor : CommonNames.raw_constructor;
8776+
let instance: Function | null = null;
8777+
// clone base constructor if a derived class. note that we cannot just
8778+
// call the base ctor since the derived class may have additional fields.
8779+
let baseClass = classInstance.base;
8780+
let contextualTypeArguments = cloneMap(classInstance.contextualTypeArguments);
8781+
if (baseClass) {
8782+
let baseCtor = this.ensureConstructor(baseClass, reportNode);
8783+
this.checkFieldInitialization(baseClass, reportNode);
8784+
instance = new Function(
8785+
name,
8786+
new FunctionPrototype(
8787+
name,
8788+
classInstance,
8789+
// declaration is important, i.e. to access optional parameter initializers
8790+
(<FunctionDeclaration>baseCtor.declaration).clone()
8791+
),
8792+
null,
8793+
Signature.create(
8794+
this.program,
8795+
baseCtor.signature.parameterTypes,
8796+
classInstance.type,
8797+
classInstance.type,
8798+
baseCtor.signature.requiredParameters,
8799+
baseCtor.signature.hasRest
8800+
),
8801+
contextualTypeArguments
8802+
);
8803+
// otherwise make a default constructor
87808804
} else {
8781-
// clone base constructor if a derived class. note that we cannot just
8782-
// call the base ctor since the derived class may have additional fields.
8783-
let baseClass = classInstance.base;
8784-
let contextualTypeArguments = cloneMap(classInstance.contextualTypeArguments);
8785-
if (baseClass) {
8786-
let baseCtor = this.ensureConstructor(baseClass, reportNode);
8787-
this.checkFieldInitialization(baseClass, reportNode);
8788-
instance = new Function(
8789-
CommonNames.constructor,
8790-
new FunctionPrototype(
8791-
CommonNames.constructor,
8792-
classInstance,
8793-
// declaration is important, i.e. to access optional parameter initializers
8794-
(<FunctionDeclaration>baseCtor.declaration).clone()
8795-
),
8796-
null,
8797-
Signature.create(
8798-
this.program,
8799-
baseCtor.signature.parameterTypes,
8800-
classInstance.type,
8801-
classInstance.type,
8802-
baseCtor.signature.requiredParameters,
8803-
baseCtor.signature.hasRest
8804-
),
8805-
contextualTypeArguments
8806-
);
8807-
8808-
// otherwise make a default constructor
8809-
} else {
8810-
instance = new Function(
8811-
CommonNames.constructor,
8812-
new FunctionPrototype(
8813-
CommonNames.constructor,
8814-
classInstance, // bound
8815-
this.program.makeNativeFunctionDeclaration(CommonNames.constructor,
8816-
CommonFlags.Instance | CommonFlags.Constructor
8817-
)
8818-
),
8819-
null,
8820-
Signature.create(this.program, [], classInstance.type, classInstance.type),
8821-
contextualTypeArguments
8822-
);
8823-
}
8805+
instance = new Function(
8806+
name,
8807+
new FunctionPrototype(
8808+
name,
8809+
classInstance, // bound
8810+
this.program.makeNativeFunctionDeclaration(name,
8811+
CommonFlags.Instance | CommonFlags.Constructor
8812+
)
8813+
),
8814+
null,
8815+
Signature.create(this.program, [], classInstance.type, classInstance.type),
8816+
contextualTypeArguments
8817+
);
8818+
}
88248819

8825-
instance.set(CommonFlags.Compiled);
8826-
instance.prototype.setResolvedInstance("", instance);
8820+
instance.prototype.setResolvedInstance("", instance);
8821+
if (isExternallyVisible) {
88278822
if (classInstance.is(CommonFlags.ModuleExport)) {
88288823
instance.set(CommonFlags.ModuleExport);
88298824
}
8830-
classInstance.constructorInstance = instance;
88318825
let members = classInstance.members;
88328826
if (!members) classInstance.members = members = new Map();
88338827
members.set(CommonNames.constructor, instance.prototype);
8828+
}
8829+
return instance;
8830+
}
88348831

8835-
let previousFlow = this.currentFlow;
8836-
let flow = instance.flow;
8837-
this.currentFlow = flow;
8832+
private compileConstructorInstance(
8833+
isExternallyVisible: bool,
8834+
instance: Function,
8835+
classInstance: Class,
8836+
reportNode: Node
8837+
): void {
8838+
instance.set(CommonFlags.Compiled);
8839+
let baseClass = classInstance.base;
8840+
let previousFlow = this.currentFlow;
8841+
let flow = instance.flow;
8842+
this.currentFlow = flow;
88388843

8839-
// generate body
8840-
let signature = instance.signature;
8841-
let module = this.module;
8842-
let sizeTypeRef = this.options.sizeTypeRef;
8843-
let stmts = new Array<ExpressionRef>();
8844+
// generate body
8845+
let signature = instance.signature;
8846+
let module = this.module;
8847+
let sizeTypeRef = this.options.sizeTypeRef;
8848+
let stmts = new Array<ExpressionRef>();
88448849

8845-
// {
8846-
// this = <COND_ALLOC>
8847-
// IF_DERIVED: this = super(this, ...args)
8848-
// this.a = X
8849-
// this.b = Y
8850-
// return this
8851-
// }
8852-
stmts.push(
8853-
this.makeConditionalAllocation(classInstance, 0)
8854-
);
8855-
if (baseClass) {
8856-
let parameterTypes = signature.parameterTypes;
8857-
let numParameters = parameterTypes.length;
8858-
let operands = new Array<ExpressionRef>(1 + numParameters);
8859-
operands[0] = module.local_get(0, sizeTypeRef);
8860-
for (let i = 1; i <= numParameters; ++i) {
8861-
operands[i] = module.local_get(i, parameterTypes[i - 1].toRef());
8862-
}
8863-
stmts.push(
8864-
module.local_set(0,
8865-
this.makeCallDirect(assert(baseClass.constructorInstance), operands, reportNode, false),
8866-
baseClass.type.isManaged
8867-
)
8868-
);
8850+
// {
8851+
// this = <COND_ALLOC>?
8852+
// IF_DERIVED: this = super(this, ...args)
8853+
// this.a = X
8854+
// this.b = Y
8855+
// return this
8856+
// }
8857+
if (isExternallyVisible) {
8858+
stmts.push(this.makeConditionalAllocation(classInstance, 0));
8859+
}
8860+
if (baseClass) {
8861+
let parameterTypes = signature.parameterTypes;
8862+
let numParameters = parameterTypes.length;
8863+
let forwardCallOperands = new Array<ExpressionRef>(1 + numParameters);
8864+
forwardCallOperands[0] = module.local_get(0, sizeTypeRef);
8865+
for (let i = 1; i <= numParameters; ++i) {
8866+
forwardCallOperands[i] = module.local_get(i, parameterTypes[i - 1].toRef());
88698867
}
8870-
this.makeFieldInitializationInConstructor(classInstance, stmts);
8868+
let baseCallConstructorInstance = baseClass.rawConstructorInstance;
8869+
if (baseCallConstructorInstance == null) baseCallConstructorInstance = assert(baseClass.constructorInstance);
88718870
stmts.push(
8872-
module.local_get(0, sizeTypeRef)
8871+
module.local_set(
8872+
0,
8873+
this.makeCallDirect(baseCallConstructorInstance, forwardCallOperands, reportNode, false),
8874+
baseClass.type.isManaged
8875+
)
88738876
);
8874-
this.currentFlow = previousFlow;
8877+
}
8878+
this.makeFieldInitializationInConstructor(classInstance, stmts);
8879+
stmts.push(module.local_get(0, sizeTypeRef));
8880+
this.currentFlow = previousFlow;
88758881

8876-
// make the function
8877-
let locals = instance.localsByIndex;
8878-
let varTypes = new Array<TypeRef>(); // of temp. vars added while compiling initializers
8879-
let numOperands = 1 + signature.parameterTypes.length;
8880-
let numLocals = locals.length;
8881-
if (numLocals > numOperands) {
8882-
for (let i = numOperands; i < numLocals; ++i) varTypes.push(locals[i].type.toRef());
8883-
}
8884-
let funcRef = module.addFunction(
8885-
instance.internalName,
8886-
signature.paramRefs,
8887-
signature.resultRefs,
8888-
varTypes,
8889-
module.flatten(stmts, sizeTypeRef)
8890-
);
8891-
instance.finalize(module, funcRef);
8882+
// make the function
8883+
let locals = instance.localsByIndex;
8884+
let varTypes = new Array<TypeRef>(); // of temp. vars added while compiling initializers
8885+
let numOperands = 1 + signature.parameterTypes.length;
8886+
let numLocals = locals.length;
8887+
if (numLocals > numOperands) {
8888+
for (let i = numOperands; i < numLocals; ++i) varTypes.push(locals[i].type.toRef());
88928889
}
8890+
let funcRef = module.addFunction(
8891+
instance.internalName,
8892+
signature.paramRefs,
8893+
signature.resultRefs,
8894+
varTypes,
8895+
module.flatten(stmts, sizeTypeRef)
8896+
);
8897+
instance.finalize(module, funcRef);
8898+
}
88938899

8900+
/** Gets the compiled constructor of the specified class or generates one if none is present. */
8901+
ensureConstructor(
8902+
/** Class wanting a constructor. */
8903+
classInstance: Class,
8904+
/** Report node. */
8905+
reportNode: Node
8906+
): Function {
8907+
let instance = classInstance.constructorInstance;
8908+
if (instance) {
8909+
// shortcut if already compiled
8910+
if (instance.is(CommonFlags.Compiled)) return instance;
8911+
// do not attempt to compile if inlined anyway
8912+
if (!instance.hasDecorator(DecoratorFlags.Inline)) this.compileFunction(instance);
8913+
} else {
8914+
instance = classInstance.constructorInstance = this.createConstructorInstance(true, classInstance, reportNode);
8915+
// TODO: maybe we can remove this function when the classInstance is finalized?
8916+
if (!classInstance.hasDecorator(DecoratorFlags.Final)) {
8917+
let rawInstance = classInstance.rawConstructorInstance = this.createConstructorInstance(false, classInstance, reportNode);
8918+
this.compileConstructorInstance(false, rawInstance, classInstance, reportNode);
8919+
}
8920+
this.compileConstructorInstance(true, instance, classInstance, reportNode);
8921+
}
88948922
return instance;
88958923
}
88968924

src/program.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4367,6 +4367,8 @@ export class Class extends TypedElement {
43674367
nextMemoryOffset: u32 = 0;
43684368
/** Constructor instance. */
43694369
constructorInstance: Function | null = null;
4370+
/** Constructor instance for inheritance. */
4371+
rawConstructorInstance: Function | null = null;
43704372
/** Operator overloads. */
43714373
operatorOverloads: Map<OperatorKind,Function> | null = null;
43724374
/** Index signature, if present. */

0 commit comments

Comments
 (0)