mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-07-06 10:01:59 +00:00
Remove noMemory option; Omit 'start' if 'main' is present; Unwrap more unnecessary blocks
This commit is contained in:
139
src/compiler.ts
139
src/compiler.ts
@ -33,7 +33,10 @@ import {
|
||||
getConstValueF32,
|
||||
getConstValueF64,
|
||||
getFunctionBody,
|
||||
getGetLocalIndex
|
||||
getGetLocalIndex,
|
||||
getBlockChildCount,
|
||||
getBlockChild,
|
||||
getBlockName
|
||||
} from "./module";
|
||||
|
||||
import {
|
||||
@ -167,8 +170,6 @@ export class Options {
|
||||
noTreeShaking: bool = false;
|
||||
/** If true, replaces assertions with nops. */
|
||||
noAssert: bool = false;
|
||||
/** If true, does not set up a memory. */
|
||||
noMemory: bool = false;
|
||||
/** If true, imports the memory provided by the embedder. */
|
||||
importMemory: bool = false;
|
||||
/** If true, imports the function table provided by the embedder. */
|
||||
@ -254,9 +255,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
/** Current type in compilation. */
|
||||
currentType: Type = Type.void;
|
||||
/** Start function being compiled. */
|
||||
startFunction: Function;
|
||||
startFunctionInstance: Function;
|
||||
/** Start function statements. */
|
||||
startFunctionBody: ExpressionRef[] = [];
|
||||
startFunctionBody: ExpressionRef[];
|
||||
/** Counting memory offset. */
|
||||
memoryOffset: I64;
|
||||
/** Memory segments being compiled. */
|
||||
@ -298,15 +299,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// initialize lookup maps, built-ins, imports, exports, etc.
|
||||
program.initialize(options);
|
||||
|
||||
// set up the start function wrapping top-level statements, of all files.
|
||||
var startFunctionPrototype = assert(program.elementsLookup.get("start"));
|
||||
assert(startFunctionPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
var startFunctionInstance = new Function(
|
||||
<FunctionPrototype>startFunctionPrototype,
|
||||
startFunctionPrototype.internalName,
|
||||
new Signature([], Type.void)
|
||||
);
|
||||
this.startFunction = startFunctionInstance;
|
||||
// set up the start function
|
||||
var startFunctionInstance = new Function(program.startFunction, "start", new Signature([], Type.void));
|
||||
this.startFunctionInstance = startFunctionInstance;
|
||||
var startFunctionBody = new Array<ExpressionRef>();
|
||||
this.startFunctionBody = startFunctionBody;
|
||||
this.currentFunction = startFunctionInstance;
|
||||
|
||||
// compile entry file(s) while traversing reachable elements
|
||||
@ -315,9 +312,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (sources[i].isEntry) this.compileSource(sources[i]);
|
||||
}
|
||||
|
||||
// compile the start function if not empty
|
||||
var startFunctionBody = this.startFunctionBody;
|
||||
if (startFunctionBody.length) {
|
||||
// compile the start function if not empty or called by main
|
||||
if (startFunctionBody.length || program.mainFunction !== null) {
|
||||
let signature = startFunctionInstance.signature;
|
||||
let funcRef = module.addFunction(
|
||||
startFunctionInstance.internalName,
|
||||
@ -330,43 +326,41 @@ export class Compiler extends DiagnosticEmitter {
|
||||
module.createBlock(null, startFunctionBody)
|
||||
);
|
||||
startFunctionInstance.finalize(module, funcRef);
|
||||
module.setStart(funcRef);
|
||||
if (!program.mainFunction) module.setStart(funcRef);
|
||||
}
|
||||
|
||||
// set up static memory segments and the heap base pointer
|
||||
if (!options.noMemory) {
|
||||
let memoryOffset = this.memoryOffset;
|
||||
memoryOffset = i64_align(memoryOffset, options.usizeType.byteSize);
|
||||
this.memoryOffset = memoryOffset;
|
||||
if (options.isWasm64) {
|
||||
module.addGlobal(
|
||||
"HEAP_BASE",
|
||||
NativeType.I64,
|
||||
false,
|
||||
module.createI64(i64_low(memoryOffset), i64_high(memoryOffset))
|
||||
);
|
||||
} else {
|
||||
module.addGlobal(
|
||||
"HEAP_BASE",
|
||||
NativeType.I32,
|
||||
false,
|
||||
module.createI32(i64_low(memoryOffset))
|
||||
);
|
||||
}
|
||||
|
||||
// determine initial page size
|
||||
let pages = i64_shr_u(i64_align(memoryOffset, 0x10000), i64_new(16, 0));
|
||||
module.setMemory(
|
||||
i64_low(pages),
|
||||
this.options.isWasm64
|
||||
? Module.MAX_MEMORY_WASM64
|
||||
: Module.MAX_MEMORY_WASM32,
|
||||
this.memorySegments,
|
||||
options.target,
|
||||
"memory"
|
||||
var memoryOffset = this.memoryOffset;
|
||||
memoryOffset = i64_align(memoryOffset, options.usizeType.byteSize);
|
||||
this.memoryOffset = memoryOffset;
|
||||
if (options.isWasm64) {
|
||||
module.addGlobal(
|
||||
"HEAP_BASE",
|
||||
NativeType.I64,
|
||||
false,
|
||||
module.createI64(i64_low(memoryOffset), i64_high(memoryOffset))
|
||||
);
|
||||
} else {
|
||||
module.addGlobal(
|
||||
"HEAP_BASE",
|
||||
NativeType.I32,
|
||||
false,
|
||||
module.createI32(i64_low(memoryOffset))
|
||||
);
|
||||
}
|
||||
|
||||
// determine initial page size
|
||||
var pages = i64_shr_u(i64_align(memoryOffset, 0x10000), i64_new(16, 0));
|
||||
module.setMemory(
|
||||
i64_low(pages),
|
||||
this.options.isWasm64
|
||||
? Module.MAX_MEMORY_WASM64
|
||||
: Module.MAX_MEMORY_WASM32,
|
||||
this.memorySegments,
|
||||
options.target,
|
||||
"memory"
|
||||
);
|
||||
|
||||
// import memory if requested (default memory is named '0' by Binaryen)
|
||||
if (options.importMemory) module.addMemoryImport("0", "env", "memory");
|
||||
|
||||
@ -415,7 +409,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// compile top-level statements
|
||||
var noTreeShaking = this.options.noTreeShaking;
|
||||
var isEntry = source.isEntry;
|
||||
var startFunction = this.startFunction;
|
||||
var startFunctionInstance = this.startFunctionInstance;
|
||||
var startFunctionBody = this.startFunctionBody;
|
||||
var statements = source.statements;
|
||||
for (let i = 0, k = statements.length; i < k; ++i) {
|
||||
@ -478,7 +472,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
default: { // otherwise a top-level statement that is part of the start function's body
|
||||
let previousFunction = this.currentFunction;
|
||||
this.currentFunction = startFunction;
|
||||
this.currentFunction = startFunctionInstance;
|
||||
startFunctionBody.push(this.compileStatement(statement));
|
||||
this.currentFunction = previousFunction;
|
||||
break;
|
||||
@ -900,7 +894,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let flow = instance.flow;
|
||||
let stmt: ExpressionRef;
|
||||
if (body.kind == NodeKind.EXPRESSION) { // () => expression
|
||||
assert(!instance.isAny(CommonFlags.CONSTRUCTOR | CommonFlags.GET | CommonFlags.SET));
|
||||
assert(!instance.isAny(CommonFlags.CONSTRUCTOR | CommonFlags.GET | CommonFlags.SET | CommonFlags.MAIN));
|
||||
assert(instance.is(CommonFlags.ARROW));
|
||||
stmt = this.compileExpression(
|
||||
(<ExpressionStatement>body).expression,
|
||||
@ -913,7 +907,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
flow.finalize();
|
||||
} else {
|
||||
assert(body.kind == NodeKind.BLOCK);
|
||||
stmt = this.compileStatement(body);
|
||||
let stmts = this.compileStatements((<BlockStatement>body).statements);
|
||||
if (instance.is(CommonFlags.MAIN)) stmts.unshift(module.createCall("start", null, NativeType.None));
|
||||
flow.finalize();
|
||||
if (isConstructor) {
|
||||
let nativeSizeType = this.options.nativeSizeType;
|
||||
@ -924,21 +919,15 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// 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);
|
||||
stmts.push(module.createGetLocal(0, nativeSizeType));
|
||||
|
||||
// if not all branches are guaranteed to allocate, also append a conditional allocation
|
||||
} else {
|
||||
let parent = assert(instance.parent);
|
||||
assert(parent.kind == ElementKind.CLASS);
|
||||
stmt = module.createBlock(null, [
|
||||
stmt,
|
||||
module.createTeeLocal(0,
|
||||
this.makeConditionalAllocate(<Class>parent, declaration.name)
|
||||
)
|
||||
], nativeSizeType);
|
||||
stmts.push(module.createTeeLocal(0,
|
||||
this.makeConditionalAllocate(<Class>parent, declaration.name)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -949,6 +938,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
declaration.signature.returnType.range
|
||||
);
|
||||
}
|
||||
stmt = !stmts.length
|
||||
? module.createNop()
|
||||
: stmts.length == 1
|
||||
? stmts[0]
|
||||
: module.createBlock(null, stmts, returnType.toNativeType());
|
||||
}
|
||||
this.currentFunction = previousFunction;
|
||||
|
||||
@ -1451,7 +1445,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
case NodeKind.TYPEDECLARATION: {
|
||||
// type declarations must be top-level because function bodies are evaluated when
|
||||
// reachaable only.
|
||||
if (this.currentFunction == this.startFunction) {
|
||||
if (this.currentFunction == this.startFunctionInstance) {
|
||||
return module.createNop();
|
||||
}
|
||||
// otherwise fall-through
|
||||
@ -1468,16 +1462,23 @@ export class Compiler extends DiagnosticEmitter {
|
||||
compileStatements(statements: Statement[]): ExpressionRef[] {
|
||||
var numStatements = statements.length;
|
||||
var stmts = new Array<ExpressionRef>(numStatements);
|
||||
var count = 0;
|
||||
stmts.length = 0;
|
||||
var flow = this.currentFunction.flow;
|
||||
for (let i = 0; i < numStatements; ++i) {
|
||||
let stmt = this.compileStatement(statements[i]);
|
||||
if (getExpressionId(stmt) != ExpressionId.Nop) {
|
||||
stmts[count++] = stmt;
|
||||
if (flow.isAny(FlowFlags.ANY_TERMINATING)) break;
|
||||
switch (getExpressionId(stmt)) {
|
||||
case ExpressionId.Block: {
|
||||
if (!getBlockName(stmt)) {
|
||||
for (let j = 0, k = getBlockChildCount(stmt); j < k; ++j) stmts.push(getBlockChild(stmt, j));
|
||||
break;
|
||||
}
|
||||
// fall-through
|
||||
}
|
||||
default: stmts.push(stmt);
|
||||
case ExpressionId.Nop:
|
||||
}
|
||||
if (flow.isAny(FlowFlags.ANY_TERMINATING)) break;
|
||||
}
|
||||
stmts.length = count;
|
||||
return stmts;
|
||||
}
|
||||
|
||||
@ -1949,7 +1950,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// top-level variables and constants become globals
|
||||
if (isKnownGlobal || (
|
||||
currentFunction == this.startFunction &&
|
||||
currentFunction == this.startFunctionInstance &&
|
||||
statement.parent && statement.parent.kind == NodeKind.SOURCE
|
||||
)) {
|
||||
// NOTE that the above condition also covers top-level variables declared with 'let', even
|
||||
|
Reference in New Issue
Block a user