mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-21 18:51:43 +00:00
directize more (eliminate table use)
This commit is contained in:
130
src/builtins.ts
130
src/builtins.ts
@ -3650,9 +3650,7 @@ export function compileCall(
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let id = classReference.ensureId(compiler); // involves compile steps
|
||||
compiler.currentType = Type.u32;
|
||||
return module.createI32(id);
|
||||
return module.createI32(classReference.ensureId());
|
||||
}
|
||||
case BuiltinSymbols.gc_mark_roots: {
|
||||
if (
|
||||
@ -3666,6 +3664,20 @@ export function compileCall(
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(BuiltinSymbols.gc_mark_roots, null, NativeType.None);
|
||||
}
|
||||
case BuiltinSymbols.gc_mark_members: {
|
||||
if (
|
||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||
checkArgsRequired(operands, 2, reportNode, compiler)
|
||||
) {
|
||||
compiler.currentType = Type.void;
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let arg0 = compiler.compileExpression(operands[0], Type.u32, ConversionKind.IMPLICIT, WrapMode.NONE);
|
||||
let arg1 = compiler.compileExpression(operands[1], compiler.options.usizeType, ConversionKind.IMPLICIT, WrapMode.NONE);
|
||||
compiler.needsTraverse = true;
|
||||
compiler.currentType = Type.void;
|
||||
return module.createCall(BuiltinSymbols.gc_mark_members, [ arg0, arg1 ], NativeType.None);
|
||||
}
|
||||
}
|
||||
|
||||
// try to defer inline asm to a concrete built-in
|
||||
@ -4101,20 +4113,112 @@ export function compileMarkRoots(compiler: Compiler): void {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO
|
||||
export function compileMarkMembers(compiler: Compiler): void {
|
||||
var program = compiler.program;
|
||||
var module = compiler.module;
|
||||
var ftype = compiler.ensureFunctionType(null, Type.void);
|
||||
var usizeType = program.options.usizeType;
|
||||
var nativeSizeType = usizeType.toNativeType();
|
||||
var nativeSizeSize = usizeType.byteSize;
|
||||
var ftype = compiler.ensureFunctionType([ Type.i32, usizeType ], Type.void);
|
||||
var managedClasses = program.managedClasses;
|
||||
var markRef = assert(program.markRef);
|
||||
var names: string[] = [ "invalid" ]; // classId=0 is invalid
|
||||
var blocks = new Array<ExpressionRef[]>();
|
||||
var lastId = 0;
|
||||
|
||||
var names = new Array<string>();
|
||||
var current = module.createSwitch(names, "invalid", module.createGetLocal(0, NativeType.I32));
|
||||
for (let [id, instance] of managedClasses) {
|
||||
assert(instance.type.isManaged(program));
|
||||
assert(id == ++lastId);
|
||||
names.push(instance.internalName);
|
||||
|
||||
module.addFunction(BuiltinSymbols.gc_mark_members, ftype, [], module.createBlock(null, [
|
||||
module.createBlock("invalid", [
|
||||
current
|
||||
]),
|
||||
module.createUnreachable()
|
||||
]));
|
||||
let traverseImpl = instance.lookupInSelf("__traverse");
|
||||
|
||||
// if a library element, check if it implements a custom traversal function
|
||||
if (instance.isDeclaredInLibrary && traverseImpl) {
|
||||
assert(traverseImpl.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
let traverseFunc = program.resolver.resolveFunction(<FunctionPrototype>traverseImpl, null);
|
||||
if (!traverseFunc || !compiler.compileFunction(traverseFunc)) {
|
||||
blocks.push([
|
||||
module.createUnreachable()
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
blocks.push([
|
||||
module.createCall(traverseFunc.internalName, [
|
||||
module.createGetLocal(1, nativeSizeType)
|
||||
], NativeType.None),
|
||||
module.createReturn()
|
||||
]);
|
||||
|
||||
// otherwise generate one
|
||||
} else {
|
||||
// traverse references assigned to own fields
|
||||
let block = new Array<ExpressionRef>();
|
||||
let members = instance.members;
|
||||
if (members) {
|
||||
for (let member of members.values()) {
|
||||
if (member.kind == ElementKind.FIELD) {
|
||||
if ((<Field>member).parent === instance) {
|
||||
let fieldType = (<Field>member).type;
|
||||
if (fieldType.isManaged(program)) {
|
||||
let fieldClass = fieldType.classReference!;
|
||||
let fieldClassId = fieldClass.ensureId();
|
||||
let fieldOffset = (<Field>member).memoryOffset;
|
||||
assert(fieldOffset >= 0);
|
||||
block.push(
|
||||
// if ($2 = value) FIELDCLASS~traverse($2)
|
||||
module.createIf(
|
||||
module.createTeeLocal(2,
|
||||
module.createLoad(
|
||||
nativeSizeSize,
|
||||
false,
|
||||
module.createGetLocal(1, nativeSizeType),
|
||||
nativeSizeType,
|
||||
fieldOffset
|
||||
)
|
||||
),
|
||||
module.createBlock(null, [
|
||||
module.createCall(markRef.internalName, [
|
||||
module.createGetLocal(2, nativeSizeType)
|
||||
], NativeType.None),
|
||||
module.createCall(BuiltinSymbols.gc_mark_members, [
|
||||
module.createI32(fieldClassId),
|
||||
module.createGetLocal(2, nativeSizeType)
|
||||
], NativeType.None)
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
block.push(module.createReturn());
|
||||
blocks.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
var current: ExpressionRef;
|
||||
if (blocks.length) {
|
||||
// create a big switch mapping class ids to traversal logic
|
||||
current = module.createBlock(names[1], [
|
||||
module.createSwitch(names, "invalid", module.createGetLocal(0, NativeType.I32))
|
||||
]);
|
||||
for (let i = 0, k = blocks.length; i < k; ++i) {
|
||||
blocks[i].unshift(current);
|
||||
current = module.createBlock(i == k - 1 ? "invalid" : names[i + 2], blocks[i]);
|
||||
}
|
||||
compiler.compileFunction(markRef);
|
||||
// wrap the function with a terminating unreachable
|
||||
current = module.createBlock(null, [
|
||||
current,
|
||||
module.createUnreachable()
|
||||
]);
|
||||
} else {
|
||||
// simplify
|
||||
current = module.createUnreachable();
|
||||
}
|
||||
module.addFunction(BuiltinSymbols.gc_mark_members, ftype, [ nativeSizeType ], current);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
compileCall as compileBuiltinCall,
|
||||
compileAbort,
|
||||
compileMarkRoots,
|
||||
compileMarkMembers,
|
||||
BuiltinSymbols
|
||||
} from "./builtins";
|
||||
|
||||
@ -392,6 +393,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (!explicitStartFunction) module.setStart(funcRef);
|
||||
}
|
||||
|
||||
// compile gc integration if necessary
|
||||
if (this.needsTraverse) {
|
||||
compileMarkRoots(this);
|
||||
compileMarkMembers(this);
|
||||
}
|
||||
|
||||
// update the heap base pointer
|
||||
var memoryOffset = this.memoryOffset;
|
||||
memoryOffset = i64_align(memoryOffset, options.usizeType.byteSize);
|
||||
@ -443,12 +450,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (file.source.isEntry) this.ensureModuleExports(file);
|
||||
}
|
||||
|
||||
// set up gc
|
||||
if (this.needsTraverse) {
|
||||
compileMarkRoots(this);
|
||||
// compileMarkMembers(this);
|
||||
}
|
||||
|
||||
// expose module capabilities
|
||||
var capabilities = Capability.NONE;
|
||||
if (program.options.isWasm64) capabilities |= Capability.WASM64;
|
||||
@ -1412,7 +1413,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
} else {
|
||||
let length = stringValue.length;
|
||||
let buffer = new Uint8Array(rtHeaderSize + (length << 1));
|
||||
program.writeRuntimeHeader(buffer, 0, stringInstance.ensureId(this), length << 1);
|
||||
program.writeRuntimeHeader(buffer, 0, stringInstance.ensureId(), length << 1);
|
||||
for (let i = 0; i < length; ++i) {
|
||||
writeI16(stringValue.charCodeAt(i), buffer, rtHeaderSize + (i << 1));
|
||||
}
|
||||
@ -1438,7 +1439,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var runtimeHeaderSize = program.runtimeHeaderSize;
|
||||
|
||||
var buf = new Uint8Array(runtimeHeaderSize + byteLength);
|
||||
program.writeRuntimeHeader(buf, 0, bufferInstance.ensureId(this), byteLength);
|
||||
program.writeRuntimeHeader(buf, 0, bufferInstance.ensureId(), byteLength);
|
||||
var pos = runtimeHeaderSize;
|
||||
var nativeType = elementType.toNativeType();
|
||||
switch (nativeType) {
|
||||
@ -1525,7 +1526,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var arrayLength = i32(bufferLength / elementType.byteSize);
|
||||
|
||||
var buf = new Uint8Array(runtimeHeaderSize + arrayInstanceSize);
|
||||
program.writeRuntimeHeader(buf, 0, arrayInstance.ensureId(this), arrayInstanceSize);
|
||||
program.writeRuntimeHeader(buf, 0, arrayInstance.ensureId(), arrayInstanceSize);
|
||||
|
||||
var bufferAddress32 = i64_low(bufferSegment.offset) + runtimeHeaderSize;
|
||||
assert(!program.options.isWasm64); // TODO
|
||||
@ -6828,7 +6829,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// makeArray(length, classId, alignLog2, staticBuffer)
|
||||
let expr = this.makeCallDirect(assert(program.makeArrayInstance), [
|
||||
module.createI32(length),
|
||||
module.createI32(arrayInstance.ensureId(this)),
|
||||
module.createI32(arrayInstance.ensureId()),
|
||||
program.options.isWasm64
|
||||
? module.createI64(elementType.alignLog2)
|
||||
: module.createI32(elementType.alignLog2),
|
||||
@ -6862,7 +6863,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
module.createSetLocal(tempThis.index,
|
||||
this.makeCallDirect(makeArrayInstance, [
|
||||
module.createI32(length),
|
||||
module.createI32(arrayInstance.ensureId(this)),
|
||||
module.createI32(arrayInstance.ensureId()),
|
||||
program.options.isWasm64
|
||||
? module.createI64(elementType.alignLog2)
|
||||
: module.createI32(elementType.alignLog2),
|
||||
@ -8123,7 +8124,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
? module.createI64(classInstance.currentMemoryOffset)
|
||||
: module.createI32(classInstance.currentMemoryOffset)
|
||||
], reportNode),
|
||||
module.createI32(classInstance.ensureId(this))
|
||||
module.createI32(classInstance.ensureId())
|
||||
], reportNode);
|
||||
}
|
||||
}
|
||||
@ -8328,7 +8329,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
module.createBreak(label,
|
||||
module.createBinary(BinaryOp.EqI32, // classId == class.id
|
||||
module.createTeeLocal(idTemp.index, idExpr),
|
||||
module.createI32(classInstance.ensureId(this))
|
||||
module.createI32(classInstance.ensureId())
|
||||
),
|
||||
module.createI32(1) // ? true
|
||||
)
|
||||
@ -8408,7 +8409,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var baseInstance = classInstance.base;
|
||||
if (baseInstance) {
|
||||
let baseType = baseInstance.type;
|
||||
let baseClassId = baseInstance.ensureId(this);
|
||||
let baseClassId = baseInstance.ensureId();
|
||||
assert(baseType.isManaged(program));
|
||||
body.push(
|
||||
// BASECLASS~traverse.call(this)
|
||||
@ -8429,7 +8430,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let fieldType = (<Field>member).type;
|
||||
if (fieldType.isManaged(program)) {
|
||||
let fieldClass = fieldType.classReference!;
|
||||
let fieldClassId = fieldClass.ensureId(this);
|
||||
let fieldClassId = fieldClass.ensureId();
|
||||
let fieldOffset = (<Field>member).memoryOffset;
|
||||
assert(fieldOffset >= 0);
|
||||
hasRefFields = true;
|
||||
|
@ -346,6 +346,8 @@ export class Program extends DiagnosticEmitter {
|
||||
instancesByName: Map<string,Element> = new Map();
|
||||
/** Classes backing basic types like `i32`. */
|
||||
typeClasses: Map<TypeKind,Class> = new Map();
|
||||
/** Managed classes contained in the program, by id. */
|
||||
managedClasses: Map<i32,Class> = new Map();
|
||||
|
||||
// runtime references
|
||||
|
||||
@ -3017,22 +3019,13 @@ export class Class extends TypedElement {
|
||||
private _id: u32 = 0;
|
||||
|
||||
/** Ensures that this class has an id. */
|
||||
ensureId(compiler: Compiler): i32 {
|
||||
ensureId(): i32 {
|
||||
var id = this._id;
|
||||
if (!id) {
|
||||
assert(!this.hasDecorator(DecoratorFlags.UNMANAGED));
|
||||
let program = this.program;
|
||||
if (program.collectorKind == CollectorKind.TRACING) {
|
||||
// tracing GC uses the function index of the iteration function as the
|
||||
// class's id so it can call the id directly, which avoids to generate
|
||||
// a helper function with a big switch mapping ids to function indexes.
|
||||
// here: might be called recursively in makeIterate, so reserve the id.
|
||||
this._id = id = compiler.makeTraverseReserve(this);
|
||||
compiler.makeTraverse(this, id);
|
||||
} else {
|
||||
// counting GC or none just increments without any iterate functions
|
||||
this._id = id = program.nextClassId++;
|
||||
}
|
||||
this._id = id = program.nextClassId++;
|
||||
program.managedClasses.set(id, this);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
Reference in New Issue
Block a user