mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 07:22:21 +00:00
Initial ArrayBuffer implementation; Conditional allocation within constructors; Explicit constructor return values
This commit is contained in:
parent
8cfc479cc0
commit
9cc0fcd611
2
dist/asc.js
vendored
2
dist/asc.js
vendored
File diff suppressed because one or more lines are too long
2
dist/asc.js.map
vendored
2
dist/asc.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -2462,44 +2462,46 @@ const allocateInternalName = "allocate_memory";
|
|||||||
/** Compiles a memory allocation for an instance of the specified class. */
|
/** Compiles a memory allocation for an instance of the specified class. */
|
||||||
export function compileAllocate(
|
export function compileAllocate(
|
||||||
compiler: Compiler,
|
compiler: Compiler,
|
||||||
cls: Class,
|
classInstance: Class,
|
||||||
reportNode: Node
|
reportNode: Node
|
||||||
): ExpressionRef {
|
): ExpressionRef {
|
||||||
var program = compiler.program;
|
var program = compiler.program;
|
||||||
assert(cls.program == program);
|
assert(classInstance.program == program);
|
||||||
var module = compiler.module;
|
var module = compiler.module;
|
||||||
var options = compiler.options;
|
var options = compiler.options;
|
||||||
|
|
||||||
var prototype = program.elementsLookup.get(allocateInternalName);
|
var allocatePrototype = program.elementsLookup.get(allocateInternalName);
|
||||||
if (!prototype) {
|
if (!allocatePrototype) {
|
||||||
program.error(
|
program.error(
|
||||||
DiagnosticCode.Cannot_find_name_0,
|
DiagnosticCode.Cannot_find_name_0,
|
||||||
reportNode.range, allocateInternalName
|
reportNode.range, allocateInternalName
|
||||||
);
|
);
|
||||||
return module.createUnreachable();
|
return module.createUnreachable();
|
||||||
}
|
}
|
||||||
if (prototype.kind != ElementKind.FUNCTION_PROTOTYPE) {
|
if (allocatePrototype.kind != ElementKind.FUNCTION_PROTOTYPE) {
|
||||||
program.error(
|
program.error(
|
||||||
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
|
DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures,
|
||||||
reportNode.range, prototype.internalName
|
reportNode.range, allocatePrototype.internalName
|
||||||
);
|
);
|
||||||
return module.createUnreachable();
|
return module.createUnreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance = (<FunctionPrototype>prototype).resolve(); // reports
|
var allocateInstance = (<FunctionPrototype>allocatePrototype).resolve(); // reports
|
||||||
if (!(instance && compiler.compileFunction(instance))) return module.createUnreachable();
|
if (!(allocateInstance && compiler.compileFunction(allocateInstance))) return module.createUnreachable();
|
||||||
|
|
||||||
compiler.currentType = cls.type;
|
compiler.currentType = classInstance.type;
|
||||||
return module.createCall(
|
return module.createCall(
|
||||||
instance.internalName, [
|
allocateInstance.internalName, [
|
||||||
options.isWasm64
|
options.isWasm64
|
||||||
? module.createI64(cls.currentMemoryOffset)
|
? module.createI64(classInstance.currentMemoryOffset)
|
||||||
: module.createI32(cls.currentMemoryOffset)
|
: module.createI32(classInstance.currentMemoryOffset)
|
||||||
],
|
],
|
||||||
options.nativeSizeType
|
options.nativeSizeType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const abortInternalName = "abort";
|
||||||
|
|
||||||
/** Compiles an abort wired to the conditionally imported 'abort' function. */
|
/** Compiles an abort wired to the conditionally imported 'abort' function. */
|
||||||
export function compileAbort(
|
export function compileAbort(
|
||||||
compiler: Compiler,
|
compiler: Compiler,
|
||||||
@ -2512,7 +2514,7 @@ export function compileAbort(
|
|||||||
var stringType = program.typesLookup.get("string"); // might be intended
|
var stringType = program.typesLookup.get("string"); // might be intended
|
||||||
if (!stringType) return module.createUnreachable();
|
if (!stringType) return module.createUnreachable();
|
||||||
|
|
||||||
var abortPrototype = program.elementsLookup.get("abort"); // might be intended
|
var abortPrototype = program.elementsLookup.get(abortInternalName); // might be intended
|
||||||
if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable();
|
if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable();
|
||||||
|
|
||||||
var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports
|
var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports
|
||||||
|
278
src/compiler.ts
278
src/compiler.ts
@ -840,7 +840,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var typeRef = this.ensureFunctionType(instance.signature);
|
var typeRef = this.ensureFunctionType(instance.signature);
|
||||||
var module = this.module;
|
var module = this.module;
|
||||||
if (body) {
|
if (body) {
|
||||||
let returnType = instance.signature.returnType;
|
let isConstructor = instance.is(CommonFlags.CONSTRUCTOR);
|
||||||
|
let returnType: Type = instance.signature.returnType;
|
||||||
|
|
||||||
// compile body
|
// compile body
|
||||||
let previousFunction = this.currentFunction;
|
let previousFunction = this.currentFunction;
|
||||||
@ -848,15 +849,43 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
let flow = instance.flow;
|
let flow = instance.flow;
|
||||||
let stmt: ExpressionRef;
|
let stmt: ExpressionRef;
|
||||||
if (body.kind == NodeKind.EXPRESSION) { // () => expression
|
if (body.kind == NodeKind.EXPRESSION) { // () => expression
|
||||||
|
assert(!instance.isAny(CommonFlags.CONSTRUCTOR | CommonFlags.GET | CommonFlags.SET));
|
||||||
assert(instance.is(CommonFlags.ARROW));
|
assert(instance.is(CommonFlags.ARROW));
|
||||||
stmt = this.compileExpression((<ExpressionStatement>body).expression, returnType);
|
stmt = this.compileExpression((<ExpressionStatement>body).expression, returnType);
|
||||||
flow.set(FlowFlags.RETURNS);
|
flow.set(FlowFlags.RETURNS);
|
||||||
} else {
|
} else {
|
||||||
assert(body.kind == NodeKind.BLOCK);
|
assert(body.kind == NodeKind.BLOCK);
|
||||||
stmt = this.compileStatement(body);
|
stmt = this.compileStatement(body);
|
||||||
|
flow.finalize();
|
||||||
|
if (isConstructor) {
|
||||||
|
let nativeSizeType = this.options.nativeSizeType;
|
||||||
|
assert(instance.is(CommonFlags.INSTANCE));
|
||||||
|
|
||||||
|
// implicitly return `this` if the constructor doesn't always return on its own
|
||||||
|
if (!flow.is(FlowFlags.RETURNS)) {
|
||||||
|
|
||||||
|
// if all branches are guaranteed to allocate, skip the final conditional allocation
|
||||||
|
if (flow.is(FlowFlags.ALLOCATES)) {
|
||||||
|
stmt = module.createBlock(null, [
|
||||||
|
stmt,
|
||||||
|
module.createGetLocal(0, nativeSizeType)
|
||||||
|
], nativeSizeType);
|
||||||
|
|
||||||
|
// if not all branches are guaranteed to allocate, also append a conditional allocation
|
||||||
|
} else {
|
||||||
|
let parent = assert(instance.memberOf);
|
||||||
|
assert(parent.kind == ElementKind.CLASS);
|
||||||
|
stmt = module.createBlock(null, [
|
||||||
|
stmt,
|
||||||
|
module.createTeeLocal(0,
|
||||||
|
makeConditionalAllocate(this, <Class>parent, declaration.name)
|
||||||
|
)
|
||||||
|
], nativeSizeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// make sure all branches return
|
// make sure all branches return
|
||||||
let allBranchesReturn = flow.finalize();
|
} else if (returnType != Type.void && !flow.is(FlowFlags.RETURNS)) {
|
||||||
if (returnType != Type.void && !allBranchesReturn) {
|
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.A_function_whose_declared_type_is_not_void_must_return_a_value,
|
DiagnosticCode.A_function_whose_declared_type_is_not_void_must_return_a_value,
|
||||||
declaration.signature.returnType.range
|
declaration.signature.returnType.range
|
||||||
@ -1272,13 +1301,15 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
var stmt = this.module.createBlock(null, this.compileStatements(statements), NativeType.None);
|
var stmt = this.module.createBlock(null, this.compileStatements(statements), NativeType.None);
|
||||||
var stmtReturns = flow.is(FlowFlags.RETURNS);
|
var stmtReturns = flow.is(FlowFlags.RETURNS);
|
||||||
|
var stmtThrows = flow.is(FlowFlags.THROWS);
|
||||||
|
var stmtAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||||
|
|
||||||
// Switch back to the parent flow
|
// Switch back to the parent flow
|
||||||
flow = flow.leaveBranchOrScope();
|
flow = flow.leaveBranchOrScope();
|
||||||
this.currentFunction.flow = flow;
|
this.currentFunction.flow = flow;
|
||||||
if (stmtReturns) {
|
if (stmtReturns) flow.set(FlowFlags.RETURNS);
|
||||||
flow.set(FlowFlags.RETURNS);
|
if (stmtThrows) flow.set(FlowFlags.THROWS);
|
||||||
}
|
if (stmtAllocates) flow.set(FlowFlags.ALLOCATES);
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1300,7 +1331,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
);
|
);
|
||||||
return module.createUnreachable();
|
return module.createUnreachable();
|
||||||
}
|
}
|
||||||
flow.set(FlowFlags.POSSIBLY_BREAKS);
|
flow.set(FlowFlags.BREAKS);
|
||||||
return module.createBreak(breakLabel);
|
return module.createBreak(breakLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1324,7 +1355,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
);
|
);
|
||||||
return module.createUnreachable();
|
return module.createUnreachable();
|
||||||
}
|
}
|
||||||
flow.set(FlowFlags.POSSIBLY_CONTINUES);
|
flow.set(FlowFlags.CONTINUES);
|
||||||
return module.createBreak(continueLabel);
|
return module.createBreak(continueLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1407,12 +1438,18 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
? this.compileExpression(<Expression>statement.incrementor, Type.void)
|
? this.compileExpression(<Expression>statement.incrementor, Type.void)
|
||||||
: module.createNop();
|
: module.createNop();
|
||||||
var body = this.compileStatement(statement.statement);
|
var body = this.compileStatement(statement.statement);
|
||||||
|
|
||||||
var alwaysReturns = !statement.condition && flow.is(FlowFlags.RETURNS);
|
var alwaysReturns = !statement.condition && flow.is(FlowFlags.RETURNS);
|
||||||
|
var alwaysThrows = !statement.condition && flow.is(FlowFlags.THROWS);
|
||||||
|
var alwaysAllocates = !statement.condition && flow.is(FlowFlags.ALLOCATES);
|
||||||
// TODO: check other always-true conditions as well, not just omitted
|
// TODO: check other always-true conditions as well, not just omitted
|
||||||
|
|
||||||
|
if (alwaysReturns) flow.set(FlowFlags.RETURNS);
|
||||||
|
if (alwaysThrows) flow.set(FlowFlags.THROWS);
|
||||||
|
if (alwaysAllocates) flow.set(FlowFlags.ALLOCATES);
|
||||||
|
|
||||||
// Switch back to the parent flow
|
// Switch back to the parent flow
|
||||||
flow = flow.leaveBranchOrScope();
|
currentFunction.flow = flow.leaveBranchOrScope();
|
||||||
currentFunction.flow = flow;
|
|
||||||
currentFunction.leaveBreakContext();
|
currentFunction.leaveBreakContext();
|
||||||
|
|
||||||
var expr = module.createBlock(breakLabel, [
|
var expr = module.createBlock(breakLabel, [
|
||||||
@ -1426,9 +1463,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
], NativeType.None))
|
], NativeType.None))
|
||||||
], NativeType.None);
|
], NativeType.None);
|
||||||
|
|
||||||
// If the loop is guaranteed to run and return, propagate that and append a hint
|
// If the loop is guaranteed to run and return, append a hint
|
||||||
if (alwaysReturns) {
|
if (alwaysReturns || alwaysThrows) {
|
||||||
flow.set(FlowFlags.RETURNS);
|
|
||||||
expr = module.createBlock(null, [
|
expr = module.createBlock(null, [
|
||||||
expr,
|
expr,
|
||||||
module.createUnreachable()
|
module.createUnreachable()
|
||||||
@ -1472,22 +1508,30 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
currentFunction.flow = flow;
|
currentFunction.flow = flow;
|
||||||
var ifTrueExpr = this.compileStatement(ifTrue);
|
var ifTrueExpr = this.compileStatement(ifTrue);
|
||||||
var ifTrueReturns = flow.is(FlowFlags.RETURNS);
|
var ifTrueReturns = flow.is(FlowFlags.RETURNS);
|
||||||
|
var ifTrueThrows = flow.is(FlowFlags.THROWS);
|
||||||
|
var ifTrueAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||||
flow = flow.leaveBranchOrScope();
|
flow = flow.leaveBranchOrScope();
|
||||||
currentFunction.flow = flow;
|
currentFunction.flow = flow;
|
||||||
|
|
||||||
var ifFalseExpr: ExpressionRef = 0;
|
var ifFalseExpr: ExpressionRef = 0;
|
||||||
var ifFalseReturns = false;
|
var ifFalseReturns = false;
|
||||||
|
var ifFalseThrows = false;
|
||||||
|
var ifFalseAllocates = false;
|
||||||
if (ifFalse) {
|
if (ifFalse) {
|
||||||
flow = flow.enterBranchOrScope();
|
flow = flow.enterBranchOrScope();
|
||||||
currentFunction.flow = flow;
|
currentFunction.flow = flow;
|
||||||
ifFalseExpr = this.compileStatement(ifFalse);
|
ifFalseExpr = this.compileStatement(ifFalse);
|
||||||
ifFalseReturns = flow.is(FlowFlags.RETURNS);
|
ifFalseReturns = flow.is(FlowFlags.RETURNS);
|
||||||
|
ifFalseThrows = flow.is(FlowFlags.THROWS);
|
||||||
|
ifFalseAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||||
flow = flow.leaveBranchOrScope();
|
flow = flow.leaveBranchOrScope();
|
||||||
currentFunction.flow = flow;
|
currentFunction.flow = flow;
|
||||||
}
|
}
|
||||||
if (ifTrueReturns && ifFalseReturns) { // not necessary to append a hint
|
|
||||||
flow.set(FlowFlags.RETURNS);
|
if (ifTrueReturns && ifFalseReturns) flow.set(FlowFlags.RETURNS);
|
||||||
}
|
if (ifTrueThrows && ifFalseThrows) flow.set(FlowFlags.THROWS);
|
||||||
|
if (ifTrueAllocates && ifFalseAllocates) flow.set(FlowFlags.ALLOCATES);
|
||||||
|
|
||||||
return module.createIf(condExpr, ifTrueExpr, ifFalseExpr);
|
return module.createIf(condExpr, ifTrueExpr, ifFalseExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1556,6 +1600,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// nest blocks in order
|
// nest blocks in order
|
||||||
var currentBlock = module.createBlock("case0|" + context, breaks, NativeType.None);
|
var currentBlock = module.createBlock("case0|" + context, breaks, NativeType.None);
|
||||||
var alwaysReturns = true;
|
var alwaysReturns = true;
|
||||||
|
var alwaysThrows = true;
|
||||||
|
var alwaysAllocates = true;
|
||||||
for (let i = 0; i < numCases; ++i) {
|
for (let i = 0; i < numCases; ++i) {
|
||||||
let case_ = cases[i];
|
let case_ = cases[i];
|
||||||
let statements = case_.statements;
|
let statements = case_.statements;
|
||||||
@ -1577,6 +1623,12 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
if (!(fallsThrough || flow.is(FlowFlags.RETURNS))) {
|
if (!(fallsThrough || flow.is(FlowFlags.RETURNS))) {
|
||||||
alwaysReturns = false; // ignore fall-throughs
|
alwaysReturns = false; // ignore fall-throughs
|
||||||
}
|
}
|
||||||
|
if (!(fallsThrough || flow.is(FlowFlags.THROWS))) {
|
||||||
|
alwaysThrows = false;
|
||||||
|
}
|
||||||
|
if (!(fallsThrough || flow.is(FlowFlags.ALLOCATES))) {
|
||||||
|
alwaysAllocates = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Switch back to the parent flow
|
// Switch back to the parent flow
|
||||||
currentFunction.flow = flow.leaveBranchOrScope();
|
currentFunction.flow = flow.leaveBranchOrScope();
|
||||||
@ -1586,9 +1638,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
currentFunction.leaveBreakContext();
|
currentFunction.leaveBreakContext();
|
||||||
|
|
||||||
// If the switch has a default and always returns, propagate that
|
// If the switch has a default and always returns, propagate that
|
||||||
if (defaultIndex >= 0 && alwaysReturns) {
|
if (defaultIndex >= 0) {
|
||||||
currentFunction.flow.set(FlowFlags.RETURNS);
|
let flow = currentFunction.flow;
|
||||||
// Binaryen understands that so we don't need a hint
|
if (alwaysReturns) flow.set(FlowFlags.RETURNS);
|
||||||
|
if (alwaysThrows) flow.set(FlowFlags.THROWS);
|
||||||
|
if (alwaysAllocates) flow.set(FlowFlags.ALLOCATES);
|
||||||
}
|
}
|
||||||
return currentBlock;
|
return currentBlock;
|
||||||
}
|
}
|
||||||
@ -1596,8 +1650,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
compileThrowStatement(statement: ThrowStatement): ExpressionRef {
|
compileThrowStatement(statement: ThrowStatement): ExpressionRef {
|
||||||
var flow = this.currentFunction.flow;
|
var flow = this.currentFunction.flow;
|
||||||
|
|
||||||
// Remember that this branch possibly throws
|
// Remember that this branch throws
|
||||||
flow.set(FlowFlags.POSSIBLY_THROWS);
|
flow.set(FlowFlags.THROWS);
|
||||||
|
|
||||||
// FIXME: without try-catch it is safe to assume RETURNS as well for now
|
// FIXME: without try-catch it is safe to assume RETURNS as well for now
|
||||||
flow.set(FlowFlags.RETURNS);
|
flow.set(FlowFlags.RETURNS);
|
||||||
@ -1791,8 +1845,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
flow.continueLabel = continueLabel;
|
flow.continueLabel = continueLabel;
|
||||||
|
|
||||||
var body = this.compileStatement(statement.statement);
|
var body = this.compileStatement(statement.statement);
|
||||||
var alwaysReturns = false && flow.is(FlowFlags.RETURNS);
|
var alwaysReturns = false; // CONDITION_IS_ALWAYS_TRUE && flow.is(FlowFlags.RETURNS);
|
||||||
// TODO: evaluate possible always-true conditions
|
// TODO: evaluate if condition is always true
|
||||||
|
|
||||||
// Switch back to the parent flow
|
// Switch back to the parent flow
|
||||||
currentFunction.flow = flow.leaveBranchOrScope();
|
currentFunction.flow = flow.leaveBranchOrScope();
|
||||||
@ -4471,6 +4525,18 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
let parent = assert(currentFunction.memberOf);
|
let parent = assert(currentFunction.memberOf);
|
||||||
assert(parent.kind == ElementKind.CLASS);
|
assert(parent.kind == ElementKind.CLASS);
|
||||||
let thisType = (<Class>parent).type;
|
let thisType = (<Class>parent).type;
|
||||||
|
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
|
||||||
|
let nativeSizeType = this.options.nativeSizeType;
|
||||||
|
let flow = currentFunction.flow;
|
||||||
|
if (!flow.is(FlowFlags.ALLOCATES)) {
|
||||||
|
flow.set(FlowFlags.ALLOCATES);
|
||||||
|
// must be conditional because `this` could have been provided by a derived class
|
||||||
|
this.currentType = thisType;
|
||||||
|
return module.createTeeLocal(0,
|
||||||
|
makeConditionalAllocate(this, <Class>parent, expression)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.currentType = thisType;
|
this.currentType = thisType;
|
||||||
return module.createGetLocal(0, thisType.toNativeType());
|
return module.createGetLocal(0, thisType.toNativeType());
|
||||||
}
|
}
|
||||||
@ -4908,70 +4974,43 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var options = this.options;
|
var options = this.options;
|
||||||
var currentFunction = this.currentFunction;
|
var currentFunction = this.currentFunction;
|
||||||
|
|
||||||
|
// obtain the class being instantiated
|
||||||
var resolved = this.program.resolveExpression( // reports
|
var resolved = this.program.resolveExpression( // reports
|
||||||
expression.expression,
|
expression.expression,
|
||||||
currentFunction
|
currentFunction
|
||||||
);
|
);
|
||||||
if (resolved) {
|
if (!resolved) return module.createUnreachable();
|
||||||
if (resolved.element.kind == ElementKind.CLASS_PROTOTYPE) {
|
if (resolved.element.kind != ElementKind.CLASS_PROTOTYPE) {
|
||||||
let prototype = <ClassPrototype>resolved.element;
|
this.error(
|
||||||
let instance = prototype.resolveUsingTypeArguments( // reports
|
DiagnosticCode.Cannot_use_new_with_an_expression_whose_type_lacks_a_construct_signature,
|
||||||
expression.typeArguments,
|
expression.expression.range
|
||||||
null,
|
);
|
||||||
expression
|
return this.module.createUnreachable();
|
||||||
);
|
|
||||||
if (instance) {
|
|
||||||
let thisExpr = compileBuiltinAllocate(this, instance, expression);
|
|
||||||
let initializers = new Array<ExpressionRef>();
|
|
||||||
|
|
||||||
// use a temp local for 'this'
|
|
||||||
let tempLocal = currentFunction.getTempLocal(options.usizeType);
|
|
||||||
initializers.push(module.createSetLocal(tempLocal.index, thisExpr));
|
|
||||||
|
|
||||||
// apply field initializers
|
|
||||||
if (instance.members) {
|
|
||||||
for (let member of instance.members.values()) {
|
|
||||||
if (member.kind == ElementKind.FIELD) {
|
|
||||||
let field = <Field>member;
|
|
||||||
let fieldDeclaration = field.prototype.declaration;
|
|
||||||
if (field.is(CommonFlags.CONST)) {
|
|
||||||
assert(false); // there are no built-in fields currently
|
|
||||||
} else if (fieldDeclaration && fieldDeclaration.initializer) {
|
|
||||||
initializers.push(module.createStore(field.type.byteSize,
|
|
||||||
module.createGetLocal(tempLocal.index, options.nativeSizeType),
|
|
||||||
this.compileExpression(fieldDeclaration.initializer, field.type),
|
|
||||||
field.type.toNativeType(),
|
|
||||||
field.memoryOffset
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply constructor
|
|
||||||
let constructorInstance = instance.constructorInstance;
|
|
||||||
if (constructorInstance) {
|
|
||||||
initializers.push(this.compileCallDirect(constructorInstance, expression.arguments, expression,
|
|
||||||
module.createGetLocal(tempLocal.index, options.nativeSizeType)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// return 'this'
|
|
||||||
initializers.push(module.createGetLocal(tempLocal.index, options.nativeSizeType));
|
|
||||||
currentFunction.freeTempLocal(tempLocal);
|
|
||||||
thisExpr = module.createBlock(null, initializers, options.nativeSizeType);
|
|
||||||
|
|
||||||
this.currentType = instance.type;
|
|
||||||
return thisExpr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.error(
|
|
||||||
DiagnosticCode.Cannot_use_new_with_an_expression_whose_type_lacks_a_construct_signature,
|
|
||||||
expression.expression.range
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return module.createUnreachable();
|
var classPrototype = <ClassPrototype>resolved.element;
|
||||||
|
var classInstance = classPrototype.resolveUsingTypeArguments( // reports
|
||||||
|
expression.typeArguments,
|
||||||
|
null,
|
||||||
|
expression
|
||||||
|
);
|
||||||
|
if (!classInstance) return module.createUnreachable();
|
||||||
|
|
||||||
|
var expr: ExpressionRef;
|
||||||
|
var constructorInstance = classInstance.constructorInstance;
|
||||||
|
|
||||||
|
// if a constructor is present, call it with a zero `this`
|
||||||
|
if (constructorInstance) {
|
||||||
|
expr = this.compileCallDirect(constructorInstance, expression.arguments, expression,
|
||||||
|
options.usizeType.toNativeZero(module)
|
||||||
|
);
|
||||||
|
|
||||||
|
// otherwise simply allocate a new instance and initialize its fields
|
||||||
|
} else {
|
||||||
|
expr = makeAllocate(this, classInstance, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentType = classInstance.type;
|
||||||
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
compileParenthesizedExpression(
|
compileParenthesizedExpression(
|
||||||
@ -5764,3 +5803,78 @@ export function makeIsTrueish(expr: ExpressionRef, type: Type, module: Module):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Makes an allocation expression for an instance of the specified class. */
|
||||||
|
export function makeAllocate(compiler: Compiler, classInstance: Class, reportNode: Node): ExpressionRef {
|
||||||
|
var module = compiler.module;
|
||||||
|
var currentFunction = compiler.currentFunction;
|
||||||
|
var nativeSizeType = compiler.options.nativeSizeType;
|
||||||
|
|
||||||
|
var tempLocal = currentFunction.getTempLocal(classInstance.type);
|
||||||
|
|
||||||
|
// allocate the necessary memory
|
||||||
|
var initializers = new Array<ExpressionRef>();
|
||||||
|
initializers.push(
|
||||||
|
module.createSetLocal(tempLocal.index,
|
||||||
|
compileBuiltinAllocate(compiler, classInstance, reportNode)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// apply field initializers
|
||||||
|
if (classInstance.members) {
|
||||||
|
for (let member of classInstance.members.values()) {
|
||||||
|
if (member.kind == ElementKind.FIELD) {
|
||||||
|
let field = <Field>member;
|
||||||
|
let fieldType = field.type;
|
||||||
|
let fieldDeclaration = field.prototype.declaration;
|
||||||
|
assert(!field.isAny(CommonFlags.CONST));
|
||||||
|
if (fieldDeclaration.initializer) { // use initializer
|
||||||
|
initializers.push(module.createStore(fieldType.byteSize,
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType),
|
||||||
|
compiler.compileExpression(fieldDeclaration.initializer, fieldType), // reports
|
||||||
|
fieldType.toNativeType(),
|
||||||
|
field.memoryOffset
|
||||||
|
));
|
||||||
|
} else { // initialize with zero
|
||||||
|
// TODO: might be unnecessary if the ctor initializes the field
|
||||||
|
initializers.push(module.createStore(field.type.byteSize,
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType),
|
||||||
|
field.type.toNativeZero(module),
|
||||||
|
field.type.toNativeType(),
|
||||||
|
field.memoryOffset
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return `this`
|
||||||
|
initializers.push(
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType)
|
||||||
|
);
|
||||||
|
|
||||||
|
currentFunction.freeTempLocal(tempLocal);
|
||||||
|
compiler.currentType = classInstance.type;
|
||||||
|
return module.createBlock(null, initializers, nativeSizeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes a conditional allocation expression inside of the constructor of the specified class. */
|
||||||
|
export function makeConditionalAllocate(compiler: Compiler, classInstance: Class, reportNode: Node): ExpressionRef {
|
||||||
|
// requires that `this` is the first local
|
||||||
|
var module = compiler.module;
|
||||||
|
var nativeSizeType = compiler.options.nativeSizeType;
|
||||||
|
compiler.currentType = classInstance.type;
|
||||||
|
return module.createIf(
|
||||||
|
nativeSizeType == NativeType.I64
|
||||||
|
? module.createBinary(
|
||||||
|
BinaryOp.NeI64,
|
||||||
|
module.createGetLocal(0, NativeType.I64),
|
||||||
|
module.createI64(0)
|
||||||
|
)
|
||||||
|
: module.createGetLocal(0, NativeType.I32),
|
||||||
|
module.createGetLocal(0, nativeSizeType),
|
||||||
|
module.createTeeLocal(0,
|
||||||
|
makeAllocate(compiler, classInstance, reportNode)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -2377,8 +2377,10 @@ export class FunctionPrototype extends Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var returnType: Type;
|
var returnType: Type;
|
||||||
if (this.is(CommonFlags.SET) || this.is(CommonFlags.CONSTRUCTOR)) {
|
if (this.is(CommonFlags.SET)) {
|
||||||
returnType = Type.void; // not annotated
|
returnType = Type.void; // not annotated
|
||||||
|
} else if (this.is(CommonFlags.CONSTRUCTOR)) {
|
||||||
|
returnType = assert(classInstance).type; // not annotated
|
||||||
} else {
|
} else {
|
||||||
let typeNode = assert(signatureNode.returnType);
|
let typeNode = assert(signatureNode.returnType);
|
||||||
let type = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports
|
let type = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports
|
||||||
@ -3157,14 +3159,28 @@ export class Interface extends Class {
|
|||||||
export const enum FlowFlags {
|
export const enum FlowFlags {
|
||||||
/** No specific conditions. */
|
/** No specific conditions. */
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
|
|
||||||
/** This branch always returns. */
|
/** This branch always returns. */
|
||||||
RETURNS = 1 << 0,
|
RETURNS = 1 << 0,
|
||||||
/** This branch possibly throws. */
|
/** This branch always throws. */
|
||||||
POSSIBLY_THROWS = 1 << 1,
|
THROWS = 1 << 1,
|
||||||
/** This branch possible breaks. */
|
/** This branch always breaks. */
|
||||||
POSSIBLY_BREAKS = 1 << 2,
|
BREAKS = 1 << 2,
|
||||||
/** This branch possible continues. */
|
/** This branch always continues. */
|
||||||
POSSIBLY_CONTINUES = 1 << 3
|
CONTINUES = 1 << 3,
|
||||||
|
/** This branch always allocates. Constructors only. */
|
||||||
|
ALLOCATES = 1 << 4,
|
||||||
|
|
||||||
|
/** This branch conditionally returns in a child branch. */
|
||||||
|
CONDITIONALLY_RETURNS = 1 << 5,
|
||||||
|
/** This branch conditionally throws in a child branch. */
|
||||||
|
CONDITIONALLY_THROWS = 1 << 6,
|
||||||
|
/** This branch conditionally breaks in a child branch. */
|
||||||
|
CONDITIONALLY_BREAKS = 1 << 7,
|
||||||
|
/** This branch conditionally continues in a child branch. */
|
||||||
|
CONDITIONALLY_CONTINUES = 1 << 8,
|
||||||
|
/** This branch conditionally allocates in a child branch. Constructors only. */
|
||||||
|
CONDITIONALLY_ALLOCATES = 1 << 9
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow evaluator. */
|
/** A control flow evaluator. */
|
||||||
@ -3200,16 +3216,18 @@ export class Flow {
|
|||||||
is(flag: FlowFlags): bool { return (this.flags & flag) == flag; }
|
is(flag: FlowFlags): bool { return (this.flags & flag) == flag; }
|
||||||
/** Sets the specified flag or flags. */
|
/** Sets the specified flag or flags. */
|
||||||
set(flag: FlowFlags): void { this.flags |= flag; }
|
set(flag: FlowFlags): void { this.flags |= flag; }
|
||||||
|
/** Unsets the specified flag or flags. */
|
||||||
|
unset(flag: FlowFlags): void { this.flags &= ~flag; }
|
||||||
|
|
||||||
/** Enters a new branch or scope and returns the new flow. */
|
/** Enters a new branch or scope and returns the new flow. */
|
||||||
enterBranchOrScope(): Flow {
|
enterBranchOrScope(): Flow {
|
||||||
var branchFlow = new Flow();
|
var branch = new Flow();
|
||||||
branchFlow.parent = this;
|
branch.parent = this;
|
||||||
branchFlow.flags = this.flags;
|
branch.flags = this.flags;
|
||||||
branchFlow.currentFunction = this.currentFunction;
|
branch.currentFunction = this.currentFunction;
|
||||||
branchFlow.continueLabel = this.continueLabel;
|
branch.continueLabel = this.continueLabel;
|
||||||
branchFlow.breakLabel = this.breakLabel;
|
branch.breakLabel = this.breakLabel;
|
||||||
return branchFlow;
|
return branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Leaves the current branch or scope and returns the parent flow. */
|
/** Leaves the current branch or scope and returns the parent flow. */
|
||||||
@ -3225,14 +3243,20 @@ export class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Propagate flags to parent
|
// Propagate flags to parent
|
||||||
if (this.is(FlowFlags.POSSIBLY_THROWS)) {
|
if (this.is(FlowFlags.RETURNS)) {
|
||||||
parent.set(FlowFlags.POSSIBLY_THROWS);
|
parent.set(FlowFlags.CONDITIONALLY_RETURNS);
|
||||||
}
|
}
|
||||||
if (this.is(FlowFlags.POSSIBLY_BREAKS) && parent.breakLabel == this.breakLabel) {
|
if (this.is(FlowFlags.THROWS)) {
|
||||||
parent.set(FlowFlags.POSSIBLY_BREAKS);
|
parent.set(FlowFlags.CONDITIONALLY_THROWS);
|
||||||
}
|
}
|
||||||
if (this.is(FlowFlags.POSSIBLY_CONTINUES) && parent.continueLabel == this.continueLabel) {
|
if (this.is(FlowFlags.BREAKS) && parent.breakLabel == this.breakLabel) {
|
||||||
parent.set(FlowFlags.POSSIBLY_CONTINUES);
|
parent.set(FlowFlags.CONDITIONALLY_BREAKS);
|
||||||
|
}
|
||||||
|
if (this.is(FlowFlags.CONTINUES) && parent.continueLabel == this.continueLabel) {
|
||||||
|
parent.set(FlowFlags.CONDITIONALLY_CONTINUES);
|
||||||
|
}
|
||||||
|
if (this.is(FlowFlags.ALLOCATES)) {
|
||||||
|
parent.set(FlowFlags.CONDITIONALLY_ALLOCATES);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent;
|
return parent;
|
||||||
@ -3265,10 +3289,9 @@ export class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Finalizes this flow. Must be the topmost parent flow of the function. */
|
/** Finalizes this flow. Must be the topmost parent flow of the function. */
|
||||||
finalize(): bool {
|
finalize(): void {
|
||||||
assert(this.parent == null, "must be the topmost parent flow");
|
assert(this.parent == null, "must be the topmost parent flow");
|
||||||
this.continueLabel = null;
|
this.continueLabel = null;
|
||||||
this.breakLabel = null;
|
this.breakLabel = null;
|
||||||
return this.is(FlowFlags.RETURNS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
std/assembly.d.ts
vendored
12
std/assembly.d.ts
vendored
@ -248,7 +248,17 @@ declare function parseI64(str: string, radix?: i32): i64;
|
|||||||
/** Parses a string to a 64-bit float. */
|
/** Parses a string to a 64-bit float. */
|
||||||
declare function parseFloat(str: string): f64;
|
declare function parseFloat(str: string): f64;
|
||||||
|
|
||||||
// Standard library (not yet implemented)
|
// Standard library
|
||||||
|
|
||||||
|
/** Class representing a generic, fixed-length raw binary data buffer. */
|
||||||
|
declare class ArrayBuffer {
|
||||||
|
/** The size, in bytes, of the array. */
|
||||||
|
readonly byteLength: i32;
|
||||||
|
/** Constructs a new array buffer of the given length in bytes. */
|
||||||
|
constructor(length: i32);
|
||||||
|
/** Returns a copy of this array buffer's bytes from begin, inclusive, up to end, exclusive. */
|
||||||
|
slice(begin?: i32, end?: i32): ArrayBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
/** Class representing a sequence of values of type `T`. */
|
/** Class representing a sequence of values of type `T`. */
|
||||||
declare class Array<T> {
|
declare class Array<T> {
|
||||||
|
29
std/assembly/arraybuffer.ts
Normal file
29
std/assembly/arraybuffer.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const HEADER_SIZE: usize = sizeof<i32>();
|
||||||
|
|
||||||
|
@unmanaged
|
||||||
|
export class ArrayBuffer {
|
||||||
|
|
||||||
|
readonly byteLength: i32;
|
||||||
|
|
||||||
|
constructor(length: i32) {
|
||||||
|
if (<u32>length > 0x7fffffff) {
|
||||||
|
throw new RangeError("Invalid array buffer length");
|
||||||
|
}
|
||||||
|
var buffer = allocate_memory(HEADER_SIZE + <usize>length);
|
||||||
|
store<i32>(buffer, length);
|
||||||
|
return changetype<ArrayBuffer>(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
slice(begin: i32 = 0, end: i32 = 0x7fffffff): ArrayBuffer {
|
||||||
|
var len = this.byteLength;
|
||||||
|
if (begin < 0) begin = max(len + begin, 0);
|
||||||
|
else begin = min(begin, len);
|
||||||
|
if (end < 0) end = max(len + end, 0);
|
||||||
|
else end = min(end, len);
|
||||||
|
var newLen = max(end - begin, 0);
|
||||||
|
var buffer = allocate_memory(HEADER_SIZE + <usize>newLen);
|
||||||
|
store<i32>(buffer, newLen);
|
||||||
|
move_memory(buffer + HEADER_SIZE, changetype<usize>(this) + HEADER_SIZE + begin, newLen);
|
||||||
|
return changetype<ArrayBuffer>(buffer);
|
||||||
|
}
|
||||||
|
}
|
10
std/portable.d.ts
vendored
10
std/portable.d.ts
vendored
@ -200,6 +200,16 @@ declare function parseFloat(str: string): f64;
|
|||||||
declare const NaN: f32 | f64;
|
declare const NaN: f32 | f64;
|
||||||
declare const Infinity: f32 | f64;
|
declare const Infinity: f32 | f64;
|
||||||
|
|
||||||
|
/** Class representing a generic, fixed-length raw binary data buffer. */
|
||||||
|
declare class ArrayBuffer {
|
||||||
|
/** The size, in bytes, of the array. */
|
||||||
|
readonly byteLength: i32;
|
||||||
|
/** Constructs a new array buffer of the given length in bytes. */
|
||||||
|
constructor(length: i32);
|
||||||
|
/** Returns a copy of this array buffer's bytes from begin, inclusive, up to end, exclusive. */
|
||||||
|
slice(begin?: i32, end?: i32): ArrayBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
declare class Array<T> {
|
declare class Array<T> {
|
||||||
[key: number]: T;
|
[key: number]: T;
|
||||||
length: i32;
|
length: i32;
|
||||||
|
2392
tests/compiler/std/arraybuffer.optimized.wat
Normal file
2392
tests/compiler/std/arraybuffer.optimized.wat
Normal file
File diff suppressed because it is too large
Load Diff
39
tests/compiler/std/arraybuffer.ts
Normal file
39
tests/compiler/std/arraybuffer.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import "allocator/arena";
|
||||||
|
|
||||||
|
var buffer = new ArrayBuffer(8);
|
||||||
|
|
||||||
|
assert(buffer.byteLength == 8);
|
||||||
|
|
||||||
|
var sliced = buffer.slice();
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 8);
|
||||||
|
assert(sliced != buffer);
|
||||||
|
|
||||||
|
sliced = buffer.slice(1);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 7);
|
||||||
|
|
||||||
|
sliced = buffer.slice(-1);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 1);
|
||||||
|
|
||||||
|
sliced = buffer.slice(1, 3);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 2);
|
||||||
|
|
||||||
|
sliced = buffer.slice(1, -1);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 6);
|
||||||
|
|
||||||
|
sliced = buffer.slice(-3, -1);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 2);
|
||||||
|
|
||||||
|
sliced = buffer.slice(-4, 42);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 4);
|
||||||
|
|
||||||
|
sliced = buffer.slice(42);
|
||||||
|
|
||||||
|
assert(sliced.byteLength == 0);
|
||||||
|
assert(sliced != null);
|
2723
tests/compiler/std/arraybuffer.untouched.wat
Normal file
2723
tests/compiler/std/arraybuffer.untouched.wat
Normal file
File diff suppressed because it is too large
Load Diff
273
tests/compiler/std/constructor.optimized.wat
Normal file
273
tests/compiler/std/constructor.optimized.wat
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
(module
|
||||||
|
(type $ii (func (param i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0))
|
||||||
|
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/emptyCtor (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/emptyCtorWithFieldInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/emptyCtorWithFieldNoInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/none (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/justFieldInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/justFieldNoInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/ctorReturns (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/b (mut i32) (i32.const 1))
|
||||||
|
(global $std/constructor/ctorConditionallyReturns (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/ctorAllocates (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/ctorConditionallyAllocates (mut i32) (i32.const 0))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 4))
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func "$(lib)/allocator/arena/allocate_memory" (; 0 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(local $2 i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.gt_u
|
||||||
|
(tee_local $2
|
||||||
|
(i32.and
|
||||||
|
(i32.add
|
||||||
|
(i32.add
|
||||||
|
(tee_local $1
|
||||||
|
(get_global "$(lib)/allocator/arena/offset")
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(i32.const 7)
|
||||||
|
)
|
||||||
|
(i32.const -8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.shl
|
||||||
|
(tee_local $0
|
||||||
|
(current_memory)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(grow_memory
|
||||||
|
(select
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $4
|
||||||
|
(tee_local $3
|
||||||
|
(i32.shr_u
|
||||||
|
(i32.and
|
||||||
|
(i32.add
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.const 65535)
|
||||||
|
)
|
||||||
|
(i32.const -65536)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.gt_s
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(grow_memory
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global "$(lib)/allocator/arena/offset"
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(func $std/constructor/EmptyCtor#constructor (; 1 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/EmptyCtorWithFieldInit#constructor (; 2 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(block (result i32)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/EmptyCtorWithFieldNoInit#constructor (; 3 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(block (result i32)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorReturns#constructor (; 4 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorConditionallyReturns#constructor (; 5 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(if
|
||||||
|
(get_global $std/constructor/b)
|
||||||
|
(return
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorConditionallyAllocates#constructor (; 6 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(if
|
||||||
|
(get_global $std/constructor/b)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 7 ;) (type $v)
|
||||||
|
(local $0 i32)
|
||||||
|
(set_global "$(lib)/allocator/arena/startOffset"
|
||||||
|
(i32.and
|
||||||
|
(i32.add
|
||||||
|
(get_global $HEAP_BASE)
|
||||||
|
(i32.const 7)
|
||||||
|
)
|
||||||
|
(i32.const -8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global "$(lib)/allocator/arena/offset"
|
||||||
|
(get_global "$(lib)/allocator/arena/startOffset")
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/emptyCtor
|
||||||
|
(call $std/constructor/EmptyCtor#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/emptyCtorWithFieldInit
|
||||||
|
(call $std/constructor/EmptyCtorWithFieldInit#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/emptyCtorWithFieldNoInit
|
||||||
|
(call $std/constructor/EmptyCtorWithFieldNoInit#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/none
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/justFieldInit
|
||||||
|
(block (result i32)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $0
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/justFieldNoInit
|
||||||
|
(block (result i32)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $0
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorReturns
|
||||||
|
(call $std/constructor/CtorReturns#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorConditionallyReturns
|
||||||
|
(call $std/constructor/CtorConditionallyReturns#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorAllocates
|
||||||
|
(call $std/constructor/EmptyCtor#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorConditionallyAllocates
|
||||||
|
(call $std/constructor/CtorConditionallyAllocates#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
86
tests/compiler/std/constructor.ts
Normal file
86
tests/compiler/std/constructor.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import "allocator/arena";
|
||||||
|
|
||||||
|
// trailing conditional allocate
|
||||||
|
class EmptyCtor {
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyCtor = new EmptyCtor();
|
||||||
|
|
||||||
|
// trailing conditional allocate with field initializer
|
||||||
|
class EmptyCtorWithFieldInit {
|
||||||
|
a: i32 = 1;
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyCtorWithFieldInit = new EmptyCtorWithFieldInit();
|
||||||
|
|
||||||
|
// trailing conditional allocate with field initialized to zero
|
||||||
|
class EmptyCtorWithFieldNoInit {
|
||||||
|
a: i32;
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyCtorWithFieldNoInit = new EmptyCtorWithFieldNoInit();
|
||||||
|
|
||||||
|
// direct allocate
|
||||||
|
class None {
|
||||||
|
}
|
||||||
|
|
||||||
|
var none = new None();
|
||||||
|
|
||||||
|
// direct allocate with field initializer
|
||||||
|
class JustFieldInit {
|
||||||
|
a: i32 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var justFieldInit = new JustFieldInit();
|
||||||
|
|
||||||
|
// direct allocate with field initialized to zero
|
||||||
|
class JustFieldNoInit {
|
||||||
|
a: i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
var justFieldNoInit = new JustFieldNoInit();
|
||||||
|
|
||||||
|
// explicit allocation with no extra checks
|
||||||
|
class CtorReturns {
|
||||||
|
constructor() {
|
||||||
|
return changetype<CtorReturns>(allocate_memory(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctorReturns = new CtorReturns();
|
||||||
|
|
||||||
|
var b: bool = true;
|
||||||
|
|
||||||
|
// explicit allocation with a trailing conditional fallback
|
||||||
|
class CtorConditionallyReturns {
|
||||||
|
constructor() {
|
||||||
|
if (b) {
|
||||||
|
return changetype<CtorConditionallyReturns>(allocate_memory(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctorConditionallyReturns = new CtorConditionallyReturns();
|
||||||
|
|
||||||
|
// implicit allocation with no extra checks
|
||||||
|
class CtorAllocates {
|
||||||
|
constructor() {
|
||||||
|
this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctorAllocates = new CtorAllocates();
|
||||||
|
|
||||||
|
// implicit allocation with a trailing conditional fallback
|
||||||
|
class CtorConditionallyAllocates {
|
||||||
|
constructor() {
|
||||||
|
if (b) {
|
||||||
|
this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctorConditionallyAllocates = new CtorConditionallyAllocates();
|
392
tests/compiler/std/constructor.untouched.wat
Normal file
392
tests/compiler/std/constructor.untouched.wat
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
(module
|
||||||
|
(type $i (func (result i32)))
|
||||||
|
(type $ii (func (param i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global "$(lib)/allocator/common/alignment/BITS" i32 (i32.const 3))
|
||||||
|
(global "$(lib)/allocator/common/alignment/SIZE" i32 (i32.const 8))
|
||||||
|
(global "$(lib)/allocator/common/alignment/MASK" i32 (i32.const 7))
|
||||||
|
(global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0))
|
||||||
|
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/emptyCtor (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/emptyCtorWithFieldInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/emptyCtorWithFieldNoInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/none (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/justFieldInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/justFieldNoInit (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/ctorReturns (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/b (mut i32) (i32.const 1))
|
||||||
|
(global $std/constructor/ctorConditionallyReturns (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/ctorAllocates (mut i32) (i32.const 0))
|
||||||
|
(global $std/constructor/ctorConditionallyAllocates (mut i32) (i32.const 0))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 4))
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func "$(lib)/allocator/arena/allocate_memory" (; 0 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(local $2 i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
(local $5 i32)
|
||||||
|
(local $6 i32)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $1
|
||||||
|
(get_global "$(lib)/allocator/arena/offset")
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.and
|
||||||
|
(i32.add
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(i32.const 7)
|
||||||
|
)
|
||||||
|
(i32.xor
|
||||||
|
(i32.const 7)
|
||||||
|
(i32.const -1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $3
|
||||||
|
(current_memory)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.gt_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.shl
|
||||||
|
(get_local $3)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(set_local $4
|
||||||
|
(i32.shr_u
|
||||||
|
(i32.and
|
||||||
|
(i32.add
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.const 65535)
|
||||||
|
)
|
||||||
|
(i32.xor
|
||||||
|
(i32.const 65535)
|
||||||
|
(i32.const -1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $5
|
||||||
|
(select
|
||||||
|
(tee_local $5
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
(tee_local $6
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i32.gt_s
|
||||||
|
(get_local $5)
|
||||||
|
(get_local $6)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(grow_memory
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(grow_memory
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global "$(lib)/allocator/arena/offset"
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/EmptyCtor#constructor (; 1 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(block
|
||||||
|
)
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/EmptyCtorWithFieldInit#constructor (; 2 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(block
|
||||||
|
)
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/EmptyCtorWithFieldNoInit#constructor (; 3 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(block
|
||||||
|
)
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorReturns#constructor (; 4 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorConditionallyReturns#constructor (; 5 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(get_global $std/constructor/b)
|
||||||
|
(return
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorAllocates#constructor (; 6 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(block
|
||||||
|
(drop
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(func $std/constructor/CtorConditionallyAllocates#constructor (; 7 ;) (type $ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(get_global $std/constructor/b)
|
||||||
|
(drop
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 8 ;) (type $v)
|
||||||
|
(local $0 i32)
|
||||||
|
(set_global "$(lib)/allocator/arena/startOffset"
|
||||||
|
(i32.and
|
||||||
|
(i32.add
|
||||||
|
(get_global $HEAP_BASE)
|
||||||
|
(i32.const 7)
|
||||||
|
)
|
||||||
|
(i32.xor
|
||||||
|
(i32.const 7)
|
||||||
|
(i32.const -1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global "$(lib)/allocator/arena/offset"
|
||||||
|
(get_global "$(lib)/allocator/arena/startOffset")
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/emptyCtor
|
||||||
|
(call $std/constructor/EmptyCtor#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/emptyCtorWithFieldInit
|
||||||
|
(call $std/constructor/EmptyCtorWithFieldInit#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/emptyCtorWithFieldNoInit
|
||||||
|
(call $std/constructor/EmptyCtorWithFieldNoInit#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/none
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $0
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/justFieldInit
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $0
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/justFieldNoInit
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $0
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorReturns
|
||||||
|
(call $std/constructor/CtorReturns#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorConditionallyReturns
|
||||||
|
(call $std/constructor/CtorConditionallyReturns#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorAllocates
|
||||||
|
(call $std/constructor/CtorAllocates#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $std/constructor/ctorConditionallyAllocates
|
||||||
|
(call $std/constructor/CtorConditionallyAllocates#constructor
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -1,6 +1,6 @@
|
|||||||
(module
|
(module
|
||||||
|
(type $ifi (func (param i32 f32) (result i32)))
|
||||||
(type $ii (func (param i32) (result i32)))
|
(type $ii (func (param i32) (result i32)))
|
||||||
(type $ifv (func (param i32 f32)))
|
|
||||||
(type $v (func))
|
(type $v (func))
|
||||||
(global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0))
|
(global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0))
|
||||||
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
|
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
|
||||||
@ -91,12 +91,33 @@
|
|||||||
)
|
)
|
||||||
(get_local $1)
|
(get_local $1)
|
||||||
)
|
)
|
||||||
(func $std/new/AClass#constructor (; 1 ;) (type $ifv) (param $0 i32) (param $1 f32)
|
(func $std/new/AClass#constructor (; 1 ;) (type $ifi) (param $0 i32) (param $1 f32) (result i32)
|
||||||
|
(local $2 i32)
|
||||||
(i32.store
|
(i32.store
|
||||||
(get_local $0)
|
(get_local $0)
|
||||||
(i32.add
|
(i32.add
|
||||||
(i32.load
|
(i32.load
|
||||||
(get_local $0)
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(block (result i32)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $2
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(f32.store offset=4
|
||||||
|
(get_local $2)
|
||||||
|
(f32.const 2)
|
||||||
|
)
|
||||||
|
(tee_local $0
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
(i32.const 1)
|
(i32.const 1)
|
||||||
)
|
)
|
||||||
@ -105,9 +126,9 @@
|
|||||||
(get_local $0)
|
(get_local $0)
|
||||||
(get_local $1)
|
(get_local $1)
|
||||||
)
|
)
|
||||||
|
(get_local $0)
|
||||||
)
|
)
|
||||||
(func $start (; 2 ;) (type $v)
|
(func $start (; 2 ;) (type $v)
|
||||||
(local $0 i32)
|
|
||||||
(set_global "$(lib)/allocator/arena/startOffset"
|
(set_global "$(lib)/allocator/arena/startOffset"
|
||||||
(i32.and
|
(i32.and
|
||||||
(i32.add
|
(i32.add
|
||||||
@ -121,24 +142,9 @@
|
|||||||
(get_global "$(lib)/allocator/arena/startOffset")
|
(get_global "$(lib)/allocator/arena/startOffset")
|
||||||
)
|
)
|
||||||
(set_global $std/new/aClass
|
(set_global $std/new/aClass
|
||||||
(block (result i32)
|
(call $std/new/AClass#constructor
|
||||||
(i32.store
|
(i32.const 0)
|
||||||
(tee_local $0
|
(f32.const 3)
|
||||||
(call "$(lib)/allocator/arena/allocate_memory"
|
|
||||||
(i32.const 8)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(i32.const 1)
|
|
||||||
)
|
|
||||||
(f32.store offset=4
|
|
||||||
(get_local $0)
|
|
||||||
(f32.const 2)
|
|
||||||
)
|
|
||||||
(call $std/new/AClass#constructor
|
|
||||||
(get_local $0)
|
|
||||||
(f32.const 3)
|
|
||||||
)
|
|
||||||
(get_local $0)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
(module
|
(module
|
||||||
(type $i (func (result i32)))
|
(type $i (func (result i32)))
|
||||||
|
(type $ifi (func (param i32 f32) (result i32)))
|
||||||
(type $ii (func (param i32) (result i32)))
|
(type $ii (func (param i32) (result i32)))
|
||||||
(type $ifv (func (param i32 f32)))
|
|
||||||
(type $v (func))
|
(type $v (func))
|
||||||
(global "$(lib)/allocator/common/alignment/BITS" i32 (i32.const 3))
|
(global "$(lib)/allocator/common/alignment/BITS" i32 (i32.const 3))
|
||||||
(global "$(lib)/allocator/common/alignment/SIZE" i32 (i32.const 8))
|
(global "$(lib)/allocator/common/alignment/SIZE" i32 (i32.const 8))
|
||||||
@ -116,23 +116,49 @@
|
|||||||
(get_local $1)
|
(get_local $1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(func $std/new/AClass#constructor (; 1 ;) (type $ifv) (param $0 i32) (param $1 f32)
|
(func $std/new/AClass#constructor (; 1 ;) (type $ifi) (param $0 i32) (param $1 f32) (result i32)
|
||||||
(i32.store
|
(local $2 i32)
|
||||||
(get_local $0)
|
(block
|
||||||
(i32.add
|
(i32.store
|
||||||
(i32.load
|
(get_local $0)
|
||||||
(get_local $0)
|
(i32.add
|
||||||
|
(i32.load
|
||||||
|
(tee_local $0
|
||||||
|
(if (result i32)
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $0
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $2
|
||||||
|
(call "$(lib)/allocator/arena/allocate_memory"
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(f32.store offset=4
|
||||||
|
(get_local $2)
|
||||||
|
(f32.const 2)
|
||||||
|
)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
)
|
)
|
||||||
(i32.const 1)
|
)
|
||||||
|
(f32.store offset=4
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(f32.store offset=4
|
(get_local $0)
|
||||||
(get_local $0)
|
|
||||||
(get_local $1)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
(func $start (; 2 ;) (type $v)
|
(func $start (; 2 ;) (type $v)
|
||||||
(local $0 i32)
|
|
||||||
(set_global "$(lib)/allocator/arena/startOffset"
|
(set_global "$(lib)/allocator/arena/startOffset"
|
||||||
(i32.and
|
(i32.and
|
||||||
(i32.add
|
(i32.add
|
||||||
@ -149,25 +175,9 @@
|
|||||||
(get_global "$(lib)/allocator/arena/startOffset")
|
(get_global "$(lib)/allocator/arena/startOffset")
|
||||||
)
|
)
|
||||||
(set_global $std/new/aClass
|
(set_global $std/new/aClass
|
||||||
(block (result i32)
|
(call $std/new/AClass#constructor
|
||||||
(set_local $0
|
(i32.const 0)
|
||||||
(call "$(lib)/allocator/arena/allocate_memory"
|
(f32.const 3)
|
||||||
(i32.const 8)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(i32.store
|
|
||||||
(get_local $0)
|
|
||||||
(i32.const 1)
|
|
||||||
)
|
|
||||||
(f32.store offset=4
|
|
||||||
(get_local $0)
|
|
||||||
(f32.const 2)
|
|
||||||
)
|
|
||||||
(call $std/new/AClass#constructor
|
|
||||||
(get_local $0)
|
|
||||||
(f32.const 3)
|
|
||||||
)
|
|
||||||
(get_local $0)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user