mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-19 09:51:33 +00:00
move stuff, run both untouched and optimized
This commit is contained in:
130
src/builtins.ts
130
src/builtins.ts
@ -5,7 +5,8 @@
|
||||
|
||||
import {
|
||||
Compiler,
|
||||
ContextualFlags
|
||||
ContextualFlags,
|
||||
RuntimeFeatures
|
||||
} from "./compiler";
|
||||
|
||||
import {
|
||||
@ -141,6 +142,7 @@ export namespace BuiltinSymbols {
|
||||
export const call_direct = "~lib/builtins/call_direct";
|
||||
export const call_indirect = "~lib/builtins/call_indirect";
|
||||
export const instantiate = "~lib/builtins/instantiate";
|
||||
export const idof = "~lib/builtins/idof";
|
||||
|
||||
export const i8 = "~lib/builtins/i8";
|
||||
export const i16 = "~lib/builtins/i16";
|
||||
@ -464,11 +466,10 @@ export namespace BuiltinSymbols {
|
||||
export const v8x16_shuffle = "~lib/builtins/v8x16.shuffle";
|
||||
|
||||
// internals
|
||||
export const HEAP_BASE = "~lib/builtins/HEAP_BASE";
|
||||
export const RTTI_BASE = "~lib/builtins/RTTI_BASE";
|
||||
export const idof = "~lib/builtins/idof";
|
||||
export const visit_globals = "~lib/builtins/__visit_globals";
|
||||
export const visit_members = "~lib/builtins/__visit_members";
|
||||
export const HEAP_BASE = "~lib/heap/HEAP_BASE";
|
||||
export const RTTI_BASE = "~lib/rt/RTTI_BASE";
|
||||
export const visit_globals = "~lib/rt/__visit_globals";
|
||||
export const visit_members = "~lib/rt/__visit_members";
|
||||
|
||||
// std/diagnostics.ts
|
||||
export const ERROR = "~lib/diagnostics/ERROR";
|
||||
@ -3557,7 +3558,7 @@ export function compileCall(
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], Type.u32, ContextualFlags.IMPLICIT);
|
||||
compiler.needsVisitGlobals = true;
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.visitGlobals;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(BuiltinSymbols.visit_globals, [ arg0 ], NativeType.None);
|
||||
}
|
||||
@ -3571,10 +3572,123 @@ export function compileCall(
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, ContextualFlags.IMPLICIT);
|
||||
let arg1 = compiler.compileExpression(operands[1], Type.u32, ContextualFlags.IMPLICIT);
|
||||
compiler.needsVisitMembers = true;
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.visitMembers;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(BuiltinSymbols.visit_members, [ arg0, arg1 ], NativeType.None);
|
||||
}
|
||||
// The following simply intercept the respective runtime calls in order to force
|
||||
// compilation of runtime functionality to the bottom of generated binaries.
|
||||
case compiler.program.visitInstance.internalName: {
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 2, reportNode, compiler) // ref, cookie
|
||||
) {
|
||||
compiler.currentType = Type.void;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, ContextualFlags.IMPLICIT);
|
||||
let arg1 = compiler.compileExpression(operands[1], Type.u32, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.visit;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(compiler.program.visitInstance.internalName, [ arg0, arg1 ], NativeType.None);
|
||||
}
|
||||
case compiler.program.retainInstance.internalName: {
|
||||
let usizeType = compiler.options.usizeType;
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 1, reportNode, compiler) // ref
|
||||
) {
|
||||
compiler.currentType = usizeType;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], usizeType, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.retain;
|
||||
compiler.currentType = usizeType;
|
||||
return module.createCall(compiler.program.retainInstance.internalName, [ arg0 ], compiler.options.nativeSizeType);
|
||||
}
|
||||
case compiler.program.retainReleaseInstance.internalName: {
|
||||
let usizeType = compiler.options.usizeType;
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 2, reportNode, compiler) // newRef, oldRef
|
||||
) {
|
||||
compiler.currentType = usizeType;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], usizeType, ContextualFlags.IMPLICIT);
|
||||
let arg1 = compiler.compileExpression(operands[1], usizeType, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.retainRelease;
|
||||
compiler.currentType = usizeType;
|
||||
return module.createCall(compiler.program.retainReleaseInstance.internalName, [ arg0, arg1 ], compiler.options.nativeSizeType);
|
||||
}
|
||||
case compiler.program.releaseInstance.internalName: {
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 1, reportNode, compiler) // ref
|
||||
) {
|
||||
compiler.currentType = Type.void;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.release;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(compiler.program.releaseInstance.internalName, [ arg0 ], NativeType.None);
|
||||
}
|
||||
case compiler.program.allocInstance.internalName: {
|
||||
let usizeType = compiler.options.usizeType;
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 2, reportNode, compiler) // size, id
|
||||
) {
|
||||
compiler.currentType = usizeType;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], usizeType, ContextualFlags.IMPLICIT);
|
||||
let arg1 = compiler.compileExpression(operands[1], Type.u32, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.alloc;
|
||||
compiler.currentType = usizeType;
|
||||
return module.createCall(compiler.program.allocInstance.internalName, [ arg0, arg1 ], compiler.options.nativeSizeType);
|
||||
}
|
||||
case compiler.program.reallocInstance.internalName: {
|
||||
let usizeType = compiler.options.usizeType;
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 2, reportNode, compiler) // ref, size
|
||||
) {
|
||||
compiler.currentType = usizeType;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], usizeType, ContextualFlags.IMPLICIT);
|
||||
let arg1 = compiler.compileExpression(operands[1], usizeType, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.realloc;
|
||||
compiler.currentType = usizeType;
|
||||
return module.createCall(compiler.program.reallocInstance.internalName, [ arg0, arg1 ], compiler.options.nativeSizeType);
|
||||
}
|
||||
case compiler.program.freeInstance.internalName: {
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 1, reportNode, compiler) // ref
|
||||
) {
|
||||
compiler.currentType = Type.void;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, ContextualFlags.IMPLICIT);
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.free;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(compiler.program.freeInstance.internalName, [ arg0 ], NativeType.None);
|
||||
}
|
||||
case compiler.program.collectInstance.internalName: {
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 0, reportNode, compiler)
|
||||
) {
|
||||
compiler.currentType = Type.void;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
compiler.runtimeFeatures |= RuntimeFeatures.collect;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(compiler.program.collectInstance.internalName, null, NativeType.None);
|
||||
}
|
||||
}
|
||||
|
||||
// try to defer inline asm to a concrete built-in
|
||||
|
@ -250,6 +250,35 @@ export const enum ContextualFlags {
|
||||
STATIC_CAPABLE = 1 << 6
|
||||
}
|
||||
|
||||
/** Runtime features to be activated by the compiler. */
|
||||
export const enum RuntimeFeatures {
|
||||
NONE = 0,
|
||||
/** Requires HEAP_BASE and heap setup. */
|
||||
HEAP = 1 << 0,
|
||||
/** Requires RTTI_BASE and RTTI setup. */
|
||||
RTTI = 1 << 1,
|
||||
/** Requires the alloc function. */
|
||||
alloc = 1 << 2,
|
||||
/** Requires the realloc function. */
|
||||
realloc = 1 << 3,
|
||||
/** Requires the free function. */
|
||||
free = 1 << 4,
|
||||
/** Requires the retain function. */
|
||||
retain = 1 << 5,
|
||||
/** Requires the retainRelease functino. */
|
||||
retainRelease = 1 << 6,
|
||||
/** Requires the release function. */
|
||||
release = 1 << 7,
|
||||
/** Requires the collect function. */
|
||||
collect = 1 << 8,
|
||||
/** Requires the visit function. */
|
||||
visit = 1 << 9,
|
||||
/** Requires the built-in globals visitor. */
|
||||
visitGlobals = 1 << 10,
|
||||
/** Requires the built-in members visitor. */
|
||||
visitMembers = 1 << 11
|
||||
}
|
||||
|
||||
/** Compiler interface. */
|
||||
export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
@ -283,22 +312,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
argcVar: GlobalRef = 0;
|
||||
/** Argument count helper setter. */
|
||||
argcSet: FunctionRef = 0;
|
||||
/** Whether HEAP_BASE is required. */
|
||||
needsHeap: bool = false;
|
||||
/** Indicates whether the __visit_globals function must be generated. */
|
||||
needsVisitGlobals: bool = false;
|
||||
/** Indicated whether the __visit_members function must be generated. */
|
||||
needsVisitMembers: bool = false;
|
||||
/** Whether RTTI is required. */
|
||||
needsRTTI: bool = false;
|
||||
/** Whether the alloc function is required. */
|
||||
needsAlloc: bool = false;
|
||||
/** Whether the retain function is required. */
|
||||
needsRetain: bool = false;
|
||||
/** Whether the retainRelease function is required. */
|
||||
needsRetainRelease: bool = false;
|
||||
/** Whether the release function is required. */
|
||||
needsRelease: bool = false;
|
||||
/** Requires runtime features. */
|
||||
runtimeFeatures: RuntimeFeatures = RuntimeFeatures.NONE;
|
||||
/** Expressions known to have skipped an autorelease. Usually function returns. */
|
||||
skippedAutoreleases: Set<ExpressionRef> = new Set();
|
||||
|
||||
@ -347,7 +362,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.currentFlow = startFunctionInstance.flow;
|
||||
this.currentBody = startFunctionBody;
|
||||
|
||||
// add a mutable heap base dummy
|
||||
// add a mutable heap and rtti base dummies
|
||||
if (options.isWasm64) {
|
||||
module.addGlobal(BuiltinSymbols.HEAP_BASE, NativeType.I64, true, module.createI64(0));
|
||||
module.addGlobal(BuiltinSymbols.RTTI_BASE, NativeType.I64, true, module.createI64(0));
|
||||
@ -383,26 +398,28 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (!explicitStartFunction) module.setStart(funcRef);
|
||||
}
|
||||
|
||||
// compile gc features if utilized. has two uses: first, whenever the compiler
|
||||
// uses these, all it has to do is set a flag to true. second, when inspecting
|
||||
// generated WATs, it's quite useful that these functions come last.
|
||||
if (this.needsAlloc) this.compileFunction(program.allocInstance);
|
||||
if (this.needsRetain) this.compileFunction(program.retainInstance);
|
||||
if (this.needsRetainRelease) this.compileFunction(program.retainReleaseInstance);
|
||||
if (this.needsRelease) this.compileFunction(program.releaseInstance);
|
||||
if (this.needsVisitGlobals) compileVisitGlobals(this);
|
||||
if (this.needsVisitMembers) compileVisitMembers(this); // called by release
|
||||
// compile runtime implementation (after actual code). note that these may modify features and order is important.
|
||||
if (this.runtimeFeatures & RuntimeFeatures.visit) this.compileFunction(program.visitInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.retain) this.compileFunction(program.retainInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.retainRelease) this.compileFunction(program.retainReleaseInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.release) this.compileFunction(program.releaseInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.collect) this.compileFunction(program.collectInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.visitGlobals) compileVisitGlobals(this);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.visitMembers) compileVisitMembers(this); // called by release
|
||||
if (this.runtimeFeatures & RuntimeFeatures.realloc) this.compileFunction(program.reallocInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.alloc) this.compileFunction(program.allocInstance);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.free) this.compileFunction(program.freeInstance);
|
||||
|
||||
// compile runtime type information
|
||||
module.removeGlobal(BuiltinSymbols.RTTI_BASE);
|
||||
if (this.needsRTTI) compileRTTI(this);
|
||||
if (this.runtimeFeatures & RuntimeFeatures.RTTI) compileRTTI(this);
|
||||
|
||||
// update the heap base pointer
|
||||
var memoryOffset = this.memoryOffset;
|
||||
memoryOffset = i64_align(memoryOffset, options.usizeType.byteSize);
|
||||
this.memoryOffset = memoryOffset;
|
||||
module.removeGlobal(BuiltinSymbols.HEAP_BASE);
|
||||
if (this.needsHeap) {
|
||||
if (this.runtimeFeatures & RuntimeFeatures.HEAP) {
|
||||
if (options.isWasm64) {
|
||||
module.addGlobal(
|
||||
BuiltinSymbols.HEAP_BASE,
|
||||
@ -833,8 +850,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// ambient builtins like 'HEAP_BASE' need to be resolved but are added explicitly
|
||||
if (global.is(CommonFlags.AMBIENT) && global.hasDecorator(DecoratorFlags.BUILTIN)) {
|
||||
if (global.internalName == BuiltinSymbols.HEAP_BASE) this.needsHeap = true;
|
||||
else if (global.internalName == BuiltinSymbols.RTTI_BASE) this.needsRTTI = true;
|
||||
if (global.internalName == BuiltinSymbols.HEAP_BASE) this.runtimeFeatures |= RuntimeFeatures.HEAP;
|
||||
else if (global.internalName == BuiltinSymbols.RTTI_BASE) this.runtimeFeatures |= RuntimeFeatures.RTTI;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2333,6 +2350,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// Switch back to the parent flow
|
||||
if (!innerFlow.isAny(FlowFlags.ANY_TERMINATING)) this.performAutoreleases(innerFlow, stmts);
|
||||
innerFlow.unset(
|
||||
FlowFlags.BREAKS |
|
||||
FlowFlags.CONDITIONALLY_BREAKS
|
||||
@ -6524,19 +6542,19 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
/** Makes retain call, retaining the expression's value. */
|
||||
makeRetain(expr: ExpressionRef): ExpressionRef {
|
||||
this.needsRetain = true;
|
||||
this.runtimeFeatures |= RuntimeFeatures.retain;
|
||||
return this.module.createCall(this.program.retainInstance.internalName, [ expr ], this.options.nativeSizeType);
|
||||
}
|
||||
|
||||
/** Makes a retainRelease call, retaining the new expression's value and releasing the old expression's value. */
|
||||
makeRetainRelease(exprNew: ExpressionRef, exprOld: ExpressionRef): ExpressionRef {
|
||||
this.needsRetainRelease = true;
|
||||
this.runtimeFeatures |= RuntimeFeatures.retainRelease;
|
||||
return this.module.createCall(this.program.retainReleaseInstance.internalName, [ exprNew, exprOld ], this.options.nativeSizeType);
|
||||
}
|
||||
|
||||
/** Makes a release call, releasing the expression's value. Changes the current type to void.*/
|
||||
makeRelease(expr: ExpressionRef): ExpressionRef {
|
||||
this.needsRelease = true;
|
||||
this.runtimeFeatures |= RuntimeFeatures.release;
|
||||
return this.module.createCall(this.program.releaseInstance.internalName, [ expr ], NativeType.None);
|
||||
}
|
||||
|
||||
@ -8846,7 +8864,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var module = this.module;
|
||||
var options = this.options;
|
||||
this.currentType = classInstance.type;
|
||||
this.needsAlloc = true;
|
||||
this.runtimeFeatures |= RuntimeFeatures.alloc;
|
||||
return module.createCall(program.allocInstance.internalName, [
|
||||
options.isWasm64
|
||||
? module.createI64(classInstance.currentMemoryOffset)
|
||||
|
@ -280,8 +280,8 @@ export abstract class DiagnosticEmitter {
|
||||
var message = DiagnosticMessage.create(code, category, arg0, arg1, arg2).withRange(range);
|
||||
if (relatedRange) message.relatedRange = relatedRange;
|
||||
this.diagnostics.push(message);
|
||||
// console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
|
||||
// console.log(<string>new Error("stack").stack);
|
||||
console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
|
||||
console.log(<string>new Error("stack").stack);
|
||||
}
|
||||
|
||||
/** Emits an informatory diagnostic message. */
|
||||
|
@ -1042,13 +1042,13 @@ export class Program extends DiagnosticEmitter {
|
||||
let flag = decoratorKindToFlag(kind);
|
||||
if (flag) {
|
||||
if (flag == DecoratorFlags.BUILTIN) {
|
||||
if (decorator.range.source.isLibrary) {
|
||||
flags |= flag;
|
||||
} else {
|
||||
if (!(acceptedFlags & flag) && !decorator.range.source.isLibrary) {
|
||||
this.error(
|
||||
DiagnosticCode.Decorator_0_is_not_valid_here,
|
||||
decorator.range, decorator.name.range.toString()
|
||||
);
|
||||
} else {
|
||||
flags |= flag;
|
||||
}
|
||||
} else if (!(acceptedFlags & flag)) {
|
||||
this.error(
|
||||
@ -1562,7 +1562,7 @@ export class Program extends DiagnosticEmitter {
|
||||
parent: Element
|
||||
): void {
|
||||
var name = declaration.name.text;
|
||||
var validDecorators = DecoratorFlags.UNSAFE;
|
||||
var validDecorators = DecoratorFlags.UNSAFE | DecoratorFlags.BUILTIN;
|
||||
if (declaration.is(CommonFlags.AMBIENT)) {
|
||||
validDecorators |= DecoratorFlags.EXTERNAL;
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user