1
0
mirror of https://github.com/fluencelabs/assemblyscript synced 2025-07-27 20:22:10 +00:00

Initial GC integration ()

This commit is contained in:
Daniel Wirtz
2018-08-02 18:23:02 +02:00
committed by GitHub
parent 671121bf70
commit dc0f271fc2
139 changed files with 7370 additions and 5016 deletions
lib
package-lock.jsonpackage.json
src
std/assembly
tests/compiler
abi.optimized.watbinary.optimized.watbinary.untouched.watbuiltins.optimized.watcall-inferred.optimized.watcall-optional.optimized.watclass-extends.optimized.watclass-overloading.optimized.watclass-with-boolean-field.optimized.watclass.optimized.watcomma.optimized.watdeclare.optimized.watdo.optimized.watenum.optimized.watexport.optimized.watexports.optimized.watfor.optimized.watfunction-expression.optimized.watfunction-types.optimized.watfunction.optimized.watgetter-setter.optimized.wati64-polyfill.optimized.watif.optimized.watif.untouched.watimport.optimized.watinfer-type.optimized.watinlining-recursive.optimized.watinlining.optimized.watinstanceof.optimized.watlogical.optimized.watmain.optimized.watmandelbrot.optimized.watmany-locals.optimized.watmemcpy.optimized.watmemmove.optimized.watmemset.optimized.watnamed-export-default.optimized.watnamed-import-default.optimized.watnamespace.optimized.watnew-without-allocator.optimized.watobject-literal.optimized.watportable-conversions.optimized.watrecursive.optimized.watreexport.optimized.watretain-i32.optimized.watscoped.optimized.watstatic-this.optimized.wat
std
switch.optimized.watswitch.untouched.watternary.optimized.wattypealias.optimized.watunary.optimized.watvoid.optimized.watwhile.optimized.wat

@@ -134,7 +134,7 @@ export function compileCall(
compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
let classType = type.classReference;
return classType != null && classType.lookupOverload(OperatorKind.INDEXED_GET) != null
return classType !== null && classType.lookupOverload(OperatorKind.INDEXED_GET) !== null
? module.createI32(1)
: module.createI32(0);
}
@@ -175,6 +175,19 @@ export function compileCall(
compiler.currentType = Type.bool;
return module.createI32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0);
}
case "isManaged": { // isManaged<T>() -> bool
if (!compiler.program.hasGC) {
compiler.currentType = Type.bool;
return module.createI32(0);
}
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
let classType = type.classReference;
return classType !== null && !classType.hasDecorator(DecoratorFlags.UNMANAGED)
? module.createI32(1)
: module.createI32(0);
}
// math
@@ -2881,25 +2894,46 @@ export function compileAllocate(
assert(classInstance.program == program);
var module = compiler.module;
var options = compiler.options;
var allocateInstance = program.memoryAllocateInstance;
if (!allocateInstance) {
program.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "memory.allocate"
);
return module.createUnreachable();
}
if (!compiler.compileFunction(allocateInstance)) return module.createUnreachable();
compiler.currentType = classInstance.type;
return module.createCall(
allocateInstance.internalName, [
options.isWasm64
? module.createI64(classInstance.currentMemoryOffset)
: module.createI32(classInstance.currentMemoryOffset)
],
options.nativeSizeType
);
// __gc_allocate(size, markFn)
if (program.hasGC && classInstance.type.isManaged(program)) {
let allocateInstance = assert(program.gcAllocateInstance);
if (!compiler.compileFunction(allocateInstance)) return module.createUnreachable();
compiler.currentType = classInstance.type;
return module.createCall(
allocateInstance.internalName, [
options.isWasm64
? module.createI64(classInstance.currentMemoryOffset)
: module.createI32(classInstance.currentMemoryOffset),
module.createI32(
ensureGCHook(compiler, classInstance)
)
],
options.nativeSizeType
);
// memory.allocate(size)
} else {
let allocateInstance = program.memoryAllocateInstance;
if (!allocateInstance) {
program.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "memory.allocate"
);
return module.createUnreachable();
}
if (!compiler.compileFunction(allocateInstance)) return module.createUnreachable();
compiler.currentType = classInstance.type;
return module.createCall(
allocateInstance.internalName, [
options.isWasm64
? module.createI64(classInstance.currentMemoryOffset)
: module.createI32(classInstance.currentMemoryOffset)
],
options.nativeSizeType
);
}
}
/** Compiles an abort wired to the conditionally imported 'abort' function. */
@@ -2921,7 +2955,7 @@ export function compileAbort(
? compiler.compileExpression(message, stringType, ConversionKind.IMPLICIT, WrapMode.NONE)
: stringType.toNativeZero(module);
var filenameArg = compiler.compileStaticString(reportNode.range.source.normalizedPath);
var filenameArg = compiler.ensureStaticString(reportNode.range.source.normalizedPath);
compiler.currentType = Type.void;
return module.createBlock(null, [
@@ -2988,3 +3022,122 @@ export function compileIterateRoots(compiler: Compiler): void {
: module.createNop()
);
}
/** Ensures that the specified class's GC hook exists and returns its function table index. */
export function ensureGCHook(
compiler: Compiler,
classInstance: Class
): u32 {
var program = compiler.program;
assert(classInstance.type.isManaged(program));
// check if the GC hook has already been created
{
let existingIndex = classInstance.gcHookIndex;
if (existingIndex != <u32>-1) return existingIndex;
}
// check if the class implements a custom GC function (only valid for internals)
var members = classInstance.members;
if (classInstance.prototype.declaration.range.source.isLibrary) {
if (members !== null && members.has("__gc")) {
let gcPrototype = assert(members.get("__gc"));
assert(gcPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
let gcInstance = assert(program.resolver.resolveFunction(<FunctionPrototype>gcPrototype, null));
assert(gcInstance.is(CommonFlags.PRIVATE | CommonFlags.INSTANCE));
assert(!gcInstance.isAny(CommonFlags.AMBIENT | CommonFlags.VIRTUAL));
assert(gcInstance.signature.parameterTypes.length == 0);
assert(gcInstance.signature.returnType == Type.void);
gcInstance.internalName = classInstance.internalName + "~gc";
assert(compiler.compileFunction(gcInstance));
let index = compiler.ensureFunctionTableEntry(gcInstance);
classInstance.gcHookIndex = index;
return index;
}
}
var module = compiler.module;
var options = compiler.options;
var nativeSizeType = options.nativeSizeType;
var nativeSizeSize = options.usizeType.byteSize;
var body = new Array<ExpressionRef>();
// nothing to mark if 'this' is null
body.push(
module.createIf(
module.createUnary(
options.isWasm64
? UnaryOp.EqzI64
: UnaryOp.EqzI32,
module.createGetLocal(0, nativeSizeType)
),
module.createReturn()
)
);
// remember the function index so we don't recurse infinitely
var functionTable = compiler.functionTable;
var gcHookIndex = functionTable.length;
functionTable.push(0);
classInstance.gcHookIndex = gcHookIndex;
// if the class extends a base class, call its hook first (calls mark)
var baseInstance = classInstance.base;
if (baseInstance) {
assert(baseInstance.type.isManaged(program));
body.push(
module.createCallIndirect(
module.createI32(
ensureGCHook(compiler, <Class>baseInstance.type.classReference)
),
[
module.createGetLocal(0, nativeSizeType)
],
nativeSizeType == NativeType.I64 ? "Iv" : "iv"
)
);
// if this class is the top-most base class, mark the instance
} else {
body.push(
module.createCall(assert(program.gcMarkInstance).internalName, [
module.createGetLocal(0, nativeSizeType)
], NativeType.None)
);
}
// mark instances assigned to own fields that are again references
if (members) {
for (let member of members.values()) {
if (member.kind == ElementKind.FIELD) {
if ((<Field>member).parent === classInstance) {
let type = (<Field>member).type;
if (type.isManaged(program)) {
let offset = (<Field>member).memoryOffset;
assert(offset >= 0);
body.push(
module.createCall(assert(program.gcMarkInstance).internalName, [
module.createLoad(
nativeSizeSize,
false,
module.createGetLocal(0, nativeSizeType),
nativeSizeType,
offset
)
], NativeType.None)
);
}
}
}
}
}
// add the function to the module and return its table index
functionTable[gcHookIndex] = module.addFunction(
classInstance.internalName + "~gc",
compiler.ensureFunctionType(null, Type.void, options.usizeType),
null,
module.createBlock(null, body)
);
return gcHookIndex;
}