diff --git a/src/builtins.ts b/src/builtins.ts index dec904e3..a0fbbbd1 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -474,6 +474,9 @@ export namespace BuiltinSymbols { export const memory_fill = "~lib/memory/memory.fill"; // std/gc.ts export const iterateRoots = "~lib/gc/iterateRoots"; + // internals + export const rt_classid = "~lib/builtins/__rt_classid"; + export const rt_iterateroots = "~lib/builtins/__rt_iterateroots"; } /** Compiles a call to a built-in function. */ @@ -3591,9 +3594,17 @@ export function compileCall( return module.createUnary(op, arg0); } - // === GC integration ========================================================================= + // === Internal runtime ======================================================================= - case BuiltinSymbols.iterateRoots: { + case BuiltinSymbols.rt_classid: { + let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); + compiler.currentType = Type.u32; + if (!type) return module.createUnreachable(); + let classReference = type.classReference; + if (!classReference) return module.createUnreachable(); + return module.createI32(classReference.prototype.classId); + } + case BuiltinSymbols.rt_iterateroots: { if ( checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 1, reportNode, compiler) diff --git a/src/program.ts b/src/program.ts index fee9a60a..a66f5c7a 100644 --- a/src/program.ts +++ b/src/program.ts @@ -344,6 +344,9 @@ export class Program extends DiagnosticEmitter { /** Memory allocation function. */ memoryAllocateInstance: Function | null = null; + /** Next class id. */ + nextClassId: u32 = 1; + // gc integration /** Whether a garbage collector is present or not. */ @@ -2355,7 +2358,7 @@ export class FunctionPrototype extends DeclaredElement { /** Constructs a new function prototype. */ constructor( - /** Simple na,e */ + /** Simple name */ name: string, /** Parent element, usually a file, namespace or class (if a method). */ parent: Element, @@ -2792,6 +2795,8 @@ export class ClassPrototype extends DeclaredElement { overloadPrototypes: Map = new Map(); /** Already resolved instances. */ instances: Map | null = null; + /** Unique class id. */ + classId: u32 = 0; constructor( /** Simple name. */ @@ -2813,6 +2818,8 @@ export class ClassPrototype extends DeclaredElement { declaration ); this.decoratorFlags = decoratorFlags; + this.classId = u32(this.program.nextClassId++); + assert(this.classId); // must not wrap around to 0 } /** Gets the associated type parameter nodes. */ diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index 3b5fc1c7..bd9c55fe 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -501,3 +501,6 @@ export namespace v8x16 { } @builtin export declare function start(): void; + +@builtin export declare function __rt_classid(): u32; +@builtin export declare function __rt_iterateroots(fn: (ref: usize) => void): void; diff --git a/std/assembly/collector/itcm.ts b/std/assembly/collector/itcm.ts index 0dbeb548..95ae1e24 100644 --- a/std/assembly/collector/itcm.ts +++ b/std/assembly/collector/itcm.ts @@ -12,7 +12,6 @@ @inline export const HEADER_SIZE: usize = (offsetof() + AL_MASK) & ~AL_MASK; import { AL_MASK, MAX_SIZE_32 } from "../internal/allocator"; -import { iterateRoots } from "../gc"; /** Collector states. */ const enum State { @@ -142,7 +141,7 @@ function step(): void { } case State.IDLE: { if (TRACE) trace("gc~step/IDLE"); - iterateRoots(__gc_mark); + __rt_iterateroots(__gc_mark); state = State.MARK; if (TRACE) trace("gc~state = MARK"); break; @@ -163,7 +162,7 @@ function step(): void { obj.hookFn(objToRef(obj)); } else { if (TRACE) trace("gc~step/MARK finish"); - iterateRoots(__gc_mark); + __rt_iterateroots(__gc_mark); obj = iter.next; if (obj === toSpace) { let from = fromSpace; diff --git a/std/assembly/gc.ts b/std/assembly/gc.ts index ceaf6d98..895e47a8 100644 --- a/std/assembly/gc.ts +++ b/std/assembly/gc.ts @@ -1,7 +1,5 @@ /* tslint:disable */ -@builtin export declare function iterateRoots(fn: (ref: usize) => void): void; - export namespace gc { export function collect(): void { diff --git a/std/assembly/internal/runtime.ts b/std/assembly/internal/runtime.ts index 377b4e6a..37a9c4af 100644 --- a/std/assembly/internal/runtime.ts +++ b/std/assembly/internal/runtime.ts @@ -25,7 +25,7 @@ export class HEADER { @inline export const HEADER_MAGIC: u32 = 0xA55E4B17; /** Aligns an allocation to actual block size. */ -function ALIGN(payloadSize: usize): usize { +export function ALIGN(payloadSize: usize): usize { // round up to power of 2, e.g. with HEADER_SIZE=8: // 0 -> 2^3 = 8 // 1..8 -> 2^4 = 16 @@ -36,7 +36,7 @@ function ALIGN(payloadSize: usize): usize { } /** Gets to the common runtime header of the specified reference. */ -function UNREF(ref: usize): HEADER { +export function UNREF(ref: usize): HEADER { assert(ref >= HEAP_BASE + HEADER_SIZE); // must be a heap object var header = changetype
(ref - HEADER_SIZE); assert(header.classId == HEADER_MAGIC); // must be unregistered @@ -96,14 +96,10 @@ export function FREE(ref: usize): void { memory.free(changetype(header)); } -function CLASSID(): u32 { - return 1; -} - /** Registers a managed object with GC. Cannot be changed anymore afterwards. */ export function REGISTER(ref: usize, parentRef: usize): void { var header = UNREF(ref); - header.classId = CLASSID(); + header.classId = __rt_classid(); if (GC) __REGISTER_IMPL(ref, parentRef); } diff --git a/std/portable/index.d.ts b/std/portable/index.d.ts index 1fbc7e41..8ce84c9d 100644 --- a/std/portable/index.d.ts +++ b/std/portable/index.d.ts @@ -142,7 +142,7 @@ declare namespace i8 { export function parseInt(string: string, radix?: i32): i8; } /** Converts any other numeric value to a 16-bit signed integer. */ -declare function i16(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare function i16(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i16; declare namespace i16 { /** Smallest representable value. */ export const MIN_VALUE: i16; @@ -178,7 +178,7 @@ declare namespace isize { export function parseInt(string: string, radix?: i32): isize; } /** Converts any other numeric value to an 8-bit unsigned integer. */ -declare function u8(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare function u8(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): u8; declare namespace u8 { /** Smallest representable value. */ export const MIN_VALUE: u8; @@ -190,7 +190,7 @@ declare namespace u8 { export function parseInt(string: string, radix?: i32): u8; } /** Converts any other numeric value to a 16-bit unsigned integer. */ -declare function u16(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i8; +declare function u16(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): u16; declare namespace u16 { /** Smallest representable value. */ export const MIN_VALUE: u16; @@ -202,7 +202,7 @@ declare namespace u16 { export function parseInt(string: string, radix?: i32): u16; } /** Converts any other numeric value to a 32-bit unsigned integer. */ -declare function u32(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): i32; +declare function u32(value: i8 | i16 | i32 | isize | u8 | u16 | u32 | usize | bool | f32 | f64): u32; declare namespace u32 { /** Smallest representable value. */ export const MIN_VALUE: u32;