mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-05-04 11:22:16 +00:00
make ref_unlink optional and itcm pass a simple test again
note: there's no marking yet
This commit is contained in:
parent
a3aa9a3961
commit
6a790321aa
@ -4041,6 +4041,7 @@ export function compileIterateRoots(compiler: Compiler): void {
|
|||||||
var exprs = new Array<ExpressionRef>();
|
var exprs = new Array<ExpressionRef>();
|
||||||
var typeName = Signature.makeSignatureString([ Type.i32 ], Type.void);
|
var typeName = Signature.makeSignatureString([ Type.i32 ], Type.void);
|
||||||
var typeRef = compiler.ensureFunctionType([ Type.i32 ], Type.void);
|
var typeRef = compiler.ensureFunctionType([ Type.i32 ], Type.void);
|
||||||
|
var nativeSizeType = compiler.options.nativeSizeType;
|
||||||
|
|
||||||
for (let element of compiler.program.elementsByName.values()) {
|
for (let element of compiler.program.elementsByName.values()) {
|
||||||
if (element.kind != ElementKind.GLOBAL) continue;
|
if (element.kind != ElementKind.GLOBAL) continue;
|
||||||
@ -4053,34 +4054,39 @@ export function compileIterateRoots(compiler: Compiler): void {
|
|||||||
) {
|
) {
|
||||||
if (global.is(CommonFlags.INLINED)) {
|
if (global.is(CommonFlags.INLINED)) {
|
||||||
let value = global.constantIntegerValue;
|
let value = global.constantIntegerValue;
|
||||||
exprs.push(
|
if (i64_low(value) || i64_high(value)) {
|
||||||
module.createCallIndirect(
|
exprs.push(
|
||||||
module.createGetLocal(0, NativeType.I32),
|
module.createCallIndirect(
|
||||||
[
|
module.createGetLocal(0, NativeType.I32),
|
||||||
compiler.options.isWasm64
|
[
|
||||||
? module.createI64(i64_low(value), i64_high(value))
|
compiler.options.isWasm64
|
||||||
: module.createI32(i64_low(value))
|
? module.createI64(i64_low(value), i64_high(value))
|
||||||
],
|
: module.createI32(i64_low(value))
|
||||||
typeName
|
],
|
||||||
)
|
typeName
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
exprs.push(
|
exprs.push(
|
||||||
module.createCallIndirect(
|
module.createIf(
|
||||||
module.createGetLocal(0, NativeType.I32),
|
module.createTeeLocal(
|
||||||
[
|
1,
|
||||||
module.createGetGlobal(
|
module.createGetGlobal(global.internalName, nativeSizeType)
|
||||||
global.internalName,
|
),
|
||||||
compiler.options.nativeSizeType
|
module.createCallIndirect(
|
||||||
)
|
module.createGetLocal(0, NativeType.I32),
|
||||||
],
|
[
|
||||||
typeName
|
module.createGetLocal(1, nativeSizeType)
|
||||||
|
],
|
||||||
|
typeName
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.addFunction("~iterateRoots", typeRef, [],
|
module.addFunction("~iterateRoots", typeRef, [ nativeSizeType ],
|
||||||
exprs.length
|
exprs.length
|
||||||
? module.createBlock(null, exprs)
|
? module.createBlock(null, exprs)
|
||||||
: module.createNop()
|
: module.createNop()
|
||||||
|
@ -8240,16 +8240,17 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var flow = this.currentFlow;
|
var flow = this.currentFlow;
|
||||||
var tempValue = flow.getTempLocal(usizeType, false);
|
var tempValue = flow.getTempLocal(usizeType, false);
|
||||||
var tempOldValue = flow.getTempLocal(usizeType, false);
|
var tempOldValue = flow.getTempLocal(usizeType, false);
|
||||||
var handleOld: ExpressionRef;
|
var handleOld: ExpressionRef = 0;
|
||||||
var handleNew: ExpressionRef;
|
var handleNew: ExpressionRef;
|
||||||
var fn1: Function | null, fn2: Function | null;
|
var fn1: Function | null, fn2: Function | null;
|
||||||
if (fn1 = program.linkRef) { // tracing
|
if (fn1 = program.linkRef) { // tracing
|
||||||
tempParent = assert(tempParent);
|
tempParent = assert(tempParent);
|
||||||
fn2 = assert(program.unlinkRef);
|
if (fn2 = program.unlinkRef) {
|
||||||
handleOld = module.createCall(fn2.internalName, [
|
handleOld = module.createCall(fn2.internalName, [
|
||||||
module.createGetLocal(tempOldValue.index, nativeSizeType),
|
module.createGetLocal(tempOldValue.index, nativeSizeType),
|
||||||
module.createGetLocal(tempParent.index, nativeSizeType)
|
module.createGetLocal(tempParent.index, nativeSizeType)
|
||||||
], NativeType.None);
|
], NativeType.None);
|
||||||
|
}
|
||||||
handleNew = module.createCall(fn1.internalName, [
|
handleNew = module.createCall(fn1.internalName, [
|
||||||
module.createGetLocal(tempValue.index, nativeSizeType),
|
module.createGetLocal(tempValue.index, nativeSizeType),
|
||||||
module.createGetLocal(tempParent.index, nativeSizeType)
|
module.createGetLocal(tempParent.index, nativeSizeType)
|
||||||
@ -8268,7 +8269,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
flow.freeTempLocal(tempValue);
|
flow.freeTempLocal(tempValue);
|
||||||
flow.freeTempLocal(tempOldValue);
|
flow.freeTempLocal(tempOldValue);
|
||||||
if (!this.compileFunction(fn1) || !this.compileFunction(fn2)) return module.createUnreachable();
|
if (!this.compileFunction(fn1)) return module.createUnreachable();
|
||||||
|
if (fn2 && !this.compileFunction(fn2)) return module.createUnreachable();
|
||||||
// if (value != oldValue) {
|
// if (value != oldValue) {
|
||||||
// if (oldValue !== null) unlink/release(oldValue[, parent])
|
// if (oldValue !== null) unlink/release(oldValue[, parent])
|
||||||
// [if (value !== null)] link/retain(value[, parent])
|
// [if (value !== null)] link/retain(value[, parent])
|
||||||
@ -8279,10 +8281,12 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
module.createTeeLocal(tempOldValue.index, oldValueExpr)
|
module.createTeeLocal(tempOldValue.index, oldValueExpr)
|
||||||
),
|
),
|
||||||
module.createBlock(null, [
|
module.createBlock(null, [
|
||||||
module.createIf(
|
handleOld
|
||||||
module.createGetLocal(tempOldValue.index, nativeSizeType),
|
? module.createIf(
|
||||||
handleOld
|
module.createGetLocal(tempOldValue.index, nativeSizeType),
|
||||||
),
|
handleOld
|
||||||
|
)
|
||||||
|
: module.createNop(),
|
||||||
nullable
|
nullable
|
||||||
? module.createIf(
|
? module.createIf(
|
||||||
module.createGetLocal(tempValue.index, nativeSizeType),
|
module.createGetLocal(tempValue.index, nativeSizeType),
|
||||||
|
@ -850,9 +850,10 @@ export class Program extends DiagnosticEmitter {
|
|||||||
if (element = this.lookupGlobal("__ref_link")) {
|
if (element = this.lookupGlobal("__ref_link")) {
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
this.linkRef = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
this.linkRef = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
element = assert(this.lookupGlobal("__ref_unlink"));
|
if (element = this.lookupGlobal("__ref_unlink")) {
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
this.unlinkRef = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
this.unlinkRef = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
|
}
|
||||||
} else if (element = this.lookupGlobal("__ref_retain")) {
|
} else if (element = this.lookupGlobal("__ref_retain")) {
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
this.retainRef = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
this.retainRef = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
|
@ -123,7 +123,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
store<T>(offset, value);
|
store<T>(offset, value);
|
||||||
if (isNullable<T>()) {
|
if (isNullable<T>()) {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_unlink)) if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
if (value !== null) __ref_link(changetype<usize>(value), changetype<usize>(this));
|
if (value !== null) __ref_link(changetype<usize>(value), changetype<usize>(this));
|
||||||
} else if (__ref_retain) {
|
} else if (__ref_retain) {
|
||||||
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
||||||
@ -131,7 +131,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
} else assert(false);
|
} else assert(false);
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_unlink)) if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
__ref_link(changetype<usize>(value), changetype<usize>(this));
|
__ref_link(changetype<usize>(value), changetype<usize>(this));
|
||||||
} else if (__ref_retain) {
|
} else if (__ref_retain) {
|
||||||
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
||||||
@ -206,7 +206,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
if (isNullable<T>()) {
|
if (isNullable<T>()) {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
if (value !== null) __ref_link(changetype<usize>(value), changetype<usize>(this));
|
if (value !== null) __ref_link(changetype<usize>(value), changetype<usize>(this));
|
||||||
if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_unlink)) if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
} else if (__ref_retain) {
|
} else if (__ref_retain) {
|
||||||
if (oldValue !== null) __ref_retain(changetype<usize>(value));
|
if (oldValue !== null) __ref_retain(changetype<usize>(value));
|
||||||
if (value !== null) __ref_release(changetype<usize>(oldValue));
|
if (value !== null) __ref_release(changetype<usize>(oldValue));
|
||||||
@ -214,7 +214,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
__ref_link(changetype<usize>(value), changetype<usize>(this));
|
__ref_link(changetype<usize>(value), changetype<usize>(this));
|
||||||
if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_unlink)) if (oldValue !== null) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
} else if (__ref_retain) {
|
} else if (__ref_retain) {
|
||||||
__ref_retain(changetype<usize>(value));
|
__ref_retain(changetype<usize>(value));
|
||||||
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
if (oldValue !== null) __ref_release(changetype<usize>(oldValue));
|
||||||
@ -476,11 +476,11 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
if (isNullable<T>()) {
|
if (isNullable<T>()) {
|
||||||
if (ref) {
|
if (ref) {
|
||||||
__ref_unlink(ref, changetype<usize>(this));
|
if (isDefined(__ref_unlink)) __ref_unlink(ref, changetype<usize>(this));
|
||||||
__ref_link(ref, changetype<usize>(result));
|
__ref_link(ref, changetype<usize>(result));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
__ref_unlink(ref, changetype<usize>(this));
|
if (isDefined(__ref_unlink)) __ref_unlink(ref, changetype<usize>(this));
|
||||||
__ref_link(ref, changetype<usize>(result));
|
__ref_link(ref, changetype<usize>(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,13 @@ Tracing
|
|||||||
Links a reference to a parent that is now referencing it.
|
Links a reference to a parent that is now referencing it.
|
||||||
|
|
||||||
* **__ref_unlink**(ref: `usize`, parentRef: `usize`): `void`<br />
|
* **__ref_unlink**(ref: `usize`, parentRef: `usize`): `void`<br />
|
||||||
Unlinks a reference from a parent that was referencing it.
|
Unlinks a reference from a parent that was referencing it. Implementation is optional.
|
||||||
|
|
||||||
Reference counting
|
Reference counting
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
* **__ref_register**(ref: `usize`): `void`<br />
|
* **__ref_register**(ref: `usize`): `void`<br />
|
||||||
Sets up a new reference. Implementation is optional for reference counting GCs.
|
Sets up a new reference. Implementation is optional.
|
||||||
|
|
||||||
* **__ref_retain**(ref: `usize`): `void`<br />
|
* **__ref_retain**(ref: `usize`): `void`<br />
|
||||||
Retains a reference, usually incrementing RC.
|
Retains a reference, usually incrementing RC.
|
||||||
@ -71,7 +71,7 @@ if (isNullable<T>()) {
|
|||||||
if (ref !== oldRef) {
|
if (ref !== oldRef) {
|
||||||
if (isNullable<T>()) {
|
if (isNullable<T>()) {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
if (oldRef) __ref_unlink(oldRef, parentRef);
|
if (isDefined(__ref_unlink)) if (oldRef) __ref_unlink(oldRef, parentRef);
|
||||||
if (ref) __ref_link(ref, parentRef);
|
if (ref) __ref_link(ref, parentRef);
|
||||||
} else if (isDefined(__ref_retain)) {
|
} else if (isDefined(__ref_retain)) {
|
||||||
if (oldRef) __ref_release(oldRef);
|
if (oldRef) __ref_release(oldRef);
|
||||||
@ -79,7 +79,7 @@ if (ref !== oldRef) {
|
|||||||
} else assert(false);
|
} else assert(false);
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
if (oldRef) __ref_unlink(oldRef, parentRef); // *
|
if (isDefined(__ref_unlink)) if (oldRef) __ref_unlink(oldRef, parentRef); // *
|
||||||
__ref_link(ref, parentRef);
|
__ref_link(ref, parentRef);
|
||||||
} else if (isDefined(__ref_retain)) {
|
} else if (isDefined(__ref_retain)) {
|
||||||
if (oldRef) __ref_release(oldRef); // *
|
if (oldRef) __ref_release(oldRef); // *
|
||||||
@ -94,13 +94,15 @@ if (ref !== oldRef) {
|
|||||||
```ts
|
```ts
|
||||||
if (isNullable<T>()) {
|
if (isNullable<T>()) {
|
||||||
if (ref) {
|
if (ref) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(ref, parentRef);
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(ref);
|
if (isDefined(__ref_unlink)) __ref_unlink(ref, parentRef);
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(ref);
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(ref, parentRef);
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(ref);
|
if (isDefined(__ref_unlink)) __ref_unlink(ref, parentRef);
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(ref);
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
5
std/assembly/collector/index.d.ts
vendored
5
std/assembly/collector/index.d.ts
vendored
@ -1,11 +1,14 @@
|
|||||||
// common
|
// common
|
||||||
declare function __ref_collect(): void;
|
declare function __ref_collect(): void;
|
||||||
|
declare function __ref_register(ref: usize): void;
|
||||||
|
|
||||||
// tracing
|
// tracing
|
||||||
declare function __ref_register(ref: usize): void;
|
|
||||||
declare function __ref_link(ref: usize, parentRef: usize): void;
|
declare function __ref_link(ref: usize, parentRef: usize): void;
|
||||||
declare function __ref_unlink(ref: usize, parentRef: usize): void;
|
declare function __ref_unlink(ref: usize, parentRef: usize): void;
|
||||||
|
|
||||||
// reference counting
|
// reference counting
|
||||||
declare function __ref_retain(ref: usize): void;
|
declare function __ref_retain(ref: usize): void;
|
||||||
declare function __ref_release(ref: usize): void;
|
declare function __ref_release(ref: usize): void;
|
||||||
|
|
||||||
|
// debugging
|
||||||
|
declare const GC_TRACE: bool;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@inline
|
@inline
|
||||||
const TRACE = false;
|
const TRACE = isDefined(GC_TRACE);
|
||||||
|
|
||||||
import { iterateRoots, HEADER_SIZE } from "../runtime";
|
import { iterateRoots, HEADER_SIZE } from "../runtime";
|
||||||
|
|
||||||
@ -85,14 +85,14 @@ var iter: ManagedObject;
|
|||||||
unlink(): void {
|
unlink(): void {
|
||||||
var next = this.next;
|
var next = this.next;
|
||||||
var prev = this.prev;
|
var prev = this.prev;
|
||||||
if (TRACE) trace(" unlink", 3, objToRef(prev), objToRef(this), objToRef(next));
|
if (TRACE) trace(" unlink [pref, ref, next]", 3, objToRef(prev), objToRef(this), objToRef(next));
|
||||||
next.prev = prev;
|
next.prev = prev;
|
||||||
prev.next = next;
|
prev.next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Marks this object as gray, that is reachable with unscanned children. */
|
/** Marks this object as gray, that is reachable with unscanned children. */
|
||||||
makeGray(): void {
|
makeGray(): void {
|
||||||
if (TRACE) trace(" makeGray", 1, objToRef(this));
|
if (TRACE) trace(" makeGray", 1, objToRef(this));
|
||||||
const gray = 2;
|
const gray = 2;
|
||||||
if (this == iter) iter = this.prev;
|
if (this == iter) iter = this.prev;
|
||||||
this.unlink();
|
this.unlink();
|
||||||
@ -107,7 +107,7 @@ var iter: ManagedObject;
|
|||||||
/** Inserts an object. */
|
/** Inserts an object. */
|
||||||
push(obj: ManagedObject): void {
|
push(obj: ManagedObject): void {
|
||||||
var prev = this.prev;
|
var prev = this.prev;
|
||||||
if (TRACE) trace(" push", 3, objToRef(prev), objToRef(obj), objToRef(this));
|
if (TRACE) trace(" push [prev, ref, next]", 3, objToRef(prev), objToRef(obj), objToRef(this));
|
||||||
obj.next = this;
|
obj.next = this;
|
||||||
obj.prev = prev;
|
obj.prev = prev;
|
||||||
prev.next = obj;
|
prev.next = obj;
|
||||||
@ -116,7 +116,7 @@ var iter: ManagedObject;
|
|||||||
|
|
||||||
/** Clears this list. */
|
/** Clears this list. */
|
||||||
clear(): void {
|
clear(): void {
|
||||||
if (TRACE) trace(" clear", 1, objToRef(this));
|
if (TRACE) trace(" clear", 1, objToRef(this));
|
||||||
this.nextWithColor = changetype<usize>(this);
|
this.nextWithColor = changetype<usize>(this);
|
||||||
this.prev = this;
|
this.prev = this;
|
||||||
}
|
}
|
||||||
@ -127,32 +127,36 @@ function step(): void {
|
|||||||
var obj: ManagedObject;
|
var obj: ManagedObject;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State.INIT: {
|
case State.INIT: {
|
||||||
if (TRACE) trace("gc~step/INIT");
|
if (TRACE) trace("itcm~step/INIT");
|
||||||
fromSpace = changetype<ManagedObjectList>(memory.allocate(HEADER_SIZE));
|
fromSpace = changetype<ManagedObjectList>(memory.allocate(HEADER_SIZE));
|
||||||
|
if (TRACE) trace(" fromSpace =", 1, objToRef(fromSpace));
|
||||||
fromSpace.classId = -1; // would error
|
fromSpace.classId = -1; // would error
|
||||||
|
fromSpace.payloadSize = 0;
|
||||||
fromSpace.clear();
|
fromSpace.clear();
|
||||||
toSpace = changetype<ManagedObjectList>(memory.allocate(HEADER_SIZE));
|
toSpace = changetype<ManagedObjectList>(memory.allocate(HEADER_SIZE));
|
||||||
|
if (TRACE) trace(" toSpace =", 1, objToRef(toSpace));
|
||||||
toSpace.classId = -1; // would error
|
toSpace.classId = -1; // would error
|
||||||
|
toSpace.payloadSize = 0;
|
||||||
toSpace.clear();
|
toSpace.clear();
|
||||||
iter = toSpace;
|
iter = toSpace;
|
||||||
state = State.IDLE;
|
state = State.IDLE;
|
||||||
if (TRACE) trace("gc~state = IDLE");
|
if (TRACE) trace("itcm~state = IDLE");
|
||||||
// fall-through
|
// fall-through
|
||||||
}
|
}
|
||||||
case State.IDLE: {
|
case State.IDLE: {
|
||||||
if (TRACE) trace("gc~step/IDLE");
|
if (TRACE) trace("itcm~step/IDLE");
|
||||||
iterateRoots((ref: usize): void => {
|
iterateRoots((ref: usize): void => {
|
||||||
var obj = refToObj(ref);
|
var obj = refToObj(ref);
|
||||||
if (obj.color == white) obj.makeGray();
|
if (obj.color == white) obj.makeGray();
|
||||||
});
|
});
|
||||||
state = State.MARK;
|
state = State.MARK;
|
||||||
if (TRACE) trace("gc~state = MARK");
|
if (TRACE) trace("itcm~state = MARK");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case State.MARK: {
|
case State.MARK: {
|
||||||
obj = iter.next;
|
obj = iter.next;
|
||||||
if (obj !== toSpace) {
|
if (obj !== toSpace) {
|
||||||
if (TRACE) trace("gc~step/MARK iterate", 1, objToRef(obj));
|
if (TRACE) trace("itcm~step/MARK iterate", 1, objToRef(obj));
|
||||||
iter = obj;
|
iter = obj;
|
||||||
obj.color = i32(!white);
|
obj.color = i32(!white);
|
||||||
// if (TRACE) {
|
// if (TRACE) {
|
||||||
@ -164,7 +168,7 @@ function step(): void {
|
|||||||
// }
|
// }
|
||||||
obj.hookFn(objToRef(obj));
|
obj.hookFn(objToRef(obj));
|
||||||
} else {
|
} else {
|
||||||
if (TRACE) trace("gc~step/MARK finish");
|
if (TRACE) trace("itcm~step/MARK finish");
|
||||||
iterateRoots((ref: usize): void => {
|
iterateRoots((ref: usize): void => {
|
||||||
var obj = refToObj(ref);
|
var obj = refToObj(ref);
|
||||||
if (obj.color == white) obj.makeGray();
|
if (obj.color == white) obj.makeGray();
|
||||||
@ -177,7 +181,7 @@ function step(): void {
|
|||||||
white = i32(!white);
|
white = i32(!white);
|
||||||
iter = from.next;
|
iter = from.next;
|
||||||
state = State.SWEEP;
|
state = State.SWEEP;
|
||||||
if (TRACE) trace("gc~state = SWEEP");
|
if (TRACE) trace("itcm~state = SWEEP");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -185,14 +189,14 @@ function step(): void {
|
|||||||
case State.SWEEP: {
|
case State.SWEEP: {
|
||||||
obj = iter;
|
obj = iter;
|
||||||
if (obj !== toSpace) {
|
if (obj !== toSpace) {
|
||||||
if (TRACE) trace("gc~step/SWEEP free", 1, objToRef(obj));
|
if (TRACE) trace("itcm~step/SWEEP free", 1, objToRef(obj));
|
||||||
iter = obj.next;
|
iter = obj.next;
|
||||||
if (changetype<usize>(obj) >= HEAP_BASE) memory.free(changetype<usize>(obj));
|
if (changetype<usize>(obj) >= HEAP_BASE) memory.free(changetype<usize>(obj));
|
||||||
} else {
|
} else {
|
||||||
if (TRACE) trace("gc~step/SWEEP finish");
|
if (TRACE) trace("itcm~step/SWEEP finish");
|
||||||
toSpace.clear();
|
toSpace.clear();
|
||||||
state = State.IDLE;
|
state = State.IDLE;
|
||||||
if (TRACE) trace("gc~state = IDLE");
|
if (TRACE) trace("itcm~state = IDLE");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -245,7 +249,7 @@ export function __ref_link(ref: usize, parentRef: usize): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@global @unsafe
|
// @global @unsafe
|
||||||
export function __ref_unlink(ref: usize, parentRef: usize): void {
|
// export function __ref_unlink(ref: usize, parentRef: usize): void {
|
||||||
if (TRACE) trace("itcm.unlink", 2, ref, parentRef);
|
// if (TRACE) trace("itcm.unlink", 2, ref, parentRef);
|
||||||
}
|
// }
|
||||||
|
@ -47,8 +47,9 @@ export class FixedArray<T> {
|
|||||||
if (value !== oldValue) {
|
if (value !== oldValue) {
|
||||||
store<T>(offset, value);
|
store<T>(offset, value);
|
||||||
if (oldValue !== null) {
|
if (oldValue !== null) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
if (isNullable<T>()) {
|
if (isNullable<T>()) {
|
||||||
|
@ -39,8 +39,9 @@ export namespace gc {
|
|||||||
if (root.has(ref)) {
|
if (root.has(ref)) {
|
||||||
root.delete(ref);
|
root.delete(ref);
|
||||||
if (implemented) {
|
if (implemented) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(ref, changetype<usize>(root));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(ref);
|
if (isDefined(__ref_unlink)) __ref_unlink(ref, changetype<usize>(root));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(ref);
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,9 @@ export class Map<K,V> {
|
|||||||
entry.value = value;
|
entry.value = value;
|
||||||
if (isNullable<V>()) {
|
if (isNullable<V>()) {
|
||||||
if (oldValue !== null) {
|
if (oldValue !== null) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
if (value !== null) {
|
if (value !== null) {
|
||||||
@ -122,7 +123,7 @@ export class Map<K,V> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) {
|
if (isDefined(__ref_link)) {
|
||||||
__ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
__ref_link(changetype<usize>(value), changetype<usize>(this));
|
__ref_link(changetype<usize>(value), changetype<usize>(this));
|
||||||
} else if (isDefined(__ref_retain)) {
|
} else if (isDefined(__ref_retain)) {
|
||||||
__ref_release(changetype<usize>(oldValue));
|
__ref_release(changetype<usize>(oldValue));
|
||||||
@ -189,13 +190,15 @@ export class Map<K,V> {
|
|||||||
let oldKey = entry.key;
|
let oldKey = entry.key;
|
||||||
if (isNullable<K>()) {
|
if (isNullable<K>()) {
|
||||||
if (oldKey !== null) {
|
if (oldKey !== null) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(oldKey), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldKey));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldKey), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldKey));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(oldKey), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldKey));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldKey), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldKey));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,13 +206,15 @@ export class Map<K,V> {
|
|||||||
let oldValue = entry.key;
|
let oldValue = entry.key;
|
||||||
if (isNullable<V>()) {
|
if (isNullable<V>()) {
|
||||||
if (oldValue !== null) {
|
if (oldValue !== null) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(oldValue), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(oldValue));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,13 +137,15 @@ export class Set<K> {
|
|||||||
key = entry.key; // exact, e.g. string
|
key = entry.key; // exact, e.g. string
|
||||||
if (isNullable<K>()) {
|
if (isNullable<K>()) {
|
||||||
if (key !== null) {
|
if (key !== null) {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(key), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(key));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(key), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(key));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(__ref_link)) __ref_unlink(changetype<usize>(key), changetype<usize>(this));
|
if (isDefined(__ref_link)) {
|
||||||
else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(key));
|
if (isDefined(__ref_unlink)) __ref_unlink(changetype<usize>(key), changetype<usize>(this));
|
||||||
|
} else if (isDefined(__ref_retain)) __ref_release(changetype<usize>(key));
|
||||||
else assert(false);
|
else assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,9 @@ tests.forEach(filename => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log("- " + colorsUtil.green("instantiate OK") + " (" + asc.formatTime(runTime) + ")");
|
console.log("- " + colorsUtil.green("instantiate OK") + " (" + asc.formatTime(runTime) + ")");
|
||||||
console.log("\n " + Object.keys(exports).map(key => "[" + (typeof exports[key]).substring(0, 3) + "] " + key).join("\n "));
|
console.log("\n " + Object.keys(exports).map(key => {
|
||||||
|
return "[" + (typeof exports[key]).substring(0, 3) + "] " + key + " = " + exports[key]
|
||||||
|
}).join("\n "));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("- " + colorsUtil.red("instantiate ERROR: ") + e.stack);
|
console.log("- " + colorsUtil.red("instantiate ERROR: ") + e.stack);
|
||||||
failed = true;
|
failed = true;
|
||||||
|
2263
tests/compiler/gc/itcm/trace.optimized.wat
Normal file
2263
tests/compiler/gc/itcm/trace.optimized.wat
Normal file
File diff suppressed because it is too large
Load Diff
26
tests/compiler/gc/itcm/trace.ts
Normal file
26
tests/compiler/gc/itcm/trace.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@global const GC_TRACE = true;
|
||||||
|
|
||||||
|
import "allocator/arena";
|
||||||
|
import "collector/itcm";
|
||||||
|
|
||||||
|
import { HEADER_SIZE } from "runtime";
|
||||||
|
|
||||||
|
assert(HEADER_SIZE == 16);
|
||||||
|
assert(gc.implemented);
|
||||||
|
|
||||||
|
gc.collect(); // trigger init
|
||||||
|
|
||||||
|
class Ref {}
|
||||||
|
|
||||||
|
trace("# ref = new Ref()");
|
||||||
|
var ref = new Ref();
|
||||||
|
trace("# arr = new Array(1)");
|
||||||
|
var arr = new Array<Ref | null>(1);
|
||||||
|
trace("# arr[0] = ref");
|
||||||
|
arr[0] = ref;
|
||||||
|
trace("# arr[0] = null");
|
||||||
|
arr[0] = null;
|
||||||
|
|
||||||
|
// TODO...
|
||||||
|
|
||||||
|
@start export function main(): void {}
|
3036
tests/compiler/gc/itcm/trace.untouched.wat
Normal file
3036
tests/compiler/gc/itcm/trace.untouched.wat
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user