mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-29 08:52:15 +00:00
decisions
This commit is contained in:
parent
139cec0846
commit
968b0321a0
@ -478,9 +478,9 @@ export namespace BuiltinSymbols {
|
|||||||
export const memory_copy = "~lib/memory/memory.copy";
|
export const memory_copy = "~lib/memory/memory.copy";
|
||||||
export const memory_fill = "~lib/memory/memory.fill";
|
export const memory_fill = "~lib/memory/memory.fill";
|
||||||
|
|
||||||
// std/gc.ts
|
// std/runtime.ts
|
||||||
export const gc_classId = "~lib/gc/gc.classId";
|
export const CLASSID = "~lib/runtime/CLASSID";
|
||||||
export const gc_iterateRoots = "~lib/gc/gc.iterateRoots";
|
export const ITERATEROOTS = "~lib/runtime/ITERATEROOTS";
|
||||||
|
|
||||||
// std/typedarray.ts
|
// std/typedarray.ts
|
||||||
export const Int8Array = "~lib/typedarray/Int8Array";
|
export const Int8Array = "~lib/typedarray/Int8Array";
|
||||||
@ -641,7 +641,7 @@ export function compileCall(
|
|||||||
return module.createI32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0);
|
return module.createI32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0);
|
||||||
}
|
}
|
||||||
case BuiltinSymbols.isManaged: { // isManaged<T>() -> bool
|
case BuiltinSymbols.isManaged: { // isManaged<T>() -> bool
|
||||||
if (!compiler.program.hasGC) {
|
if (!compiler.program.gcImplemented) {
|
||||||
compiler.currentType = Type.bool;
|
compiler.currentType = Type.bool;
|
||||||
return module.createI32(0);
|
return module.createI32(0);
|
||||||
}
|
}
|
||||||
@ -3621,7 +3621,7 @@ export function compileCall(
|
|||||||
|
|
||||||
// === Internal runtime =======================================================================
|
// === Internal runtime =======================================================================
|
||||||
|
|
||||||
case BuiltinSymbols.gc_classId: {
|
case BuiltinSymbols.CLASSID: {
|
||||||
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
||||||
compiler.currentType = Type.u32;
|
compiler.currentType = Type.u32;
|
||||||
if (!type) return module.createUnreachable();
|
if (!type) return module.createUnreachable();
|
||||||
@ -3629,7 +3629,7 @@ export function compileCall(
|
|||||||
if (!classReference) return module.createUnreachable();
|
if (!classReference) return module.createUnreachable();
|
||||||
return module.createI32(classReference.id);
|
return module.createI32(classReference.id);
|
||||||
}
|
}
|
||||||
case BuiltinSymbols.gc_iterateRoots: {
|
case BuiltinSymbols.ITERATEROOTS: {
|
||||||
if (
|
if (
|
||||||
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
checkTypeAbsent(typeArguments, reportNode, prototype) |
|
||||||
checkArgsRequired(operands, 1, reportNode, compiler)
|
checkArgsRequired(operands, 1, reportNode, compiler)
|
||||||
|
@ -179,10 +179,14 @@ export namespace LibrarySymbols {
|
|||||||
export const Math = "Math";
|
export const Math = "Math";
|
||||||
export const Mathf = "Mathf";
|
export const Mathf = "Mathf";
|
||||||
// runtime
|
// runtime
|
||||||
export const memory = "memory";
|
|
||||||
export const allocate = "allocate";
|
|
||||||
export const abort = "abort";
|
export const abort = "abort";
|
||||||
export const main = "main";
|
export const ALLOCATE = "ALLOCATE";
|
||||||
|
export const REALLOCATE = "REALLOCATE";
|
||||||
|
export const DISCARD = "DISCARD";
|
||||||
|
// gc
|
||||||
|
export const gc = "gc";
|
||||||
|
export const register = "register";
|
||||||
|
export const link = "link";
|
||||||
// other
|
// other
|
||||||
export const length = "length";
|
export const length = "length";
|
||||||
export const byteLength = "byteLength";
|
export const byteLength = "byteLength";
|
||||||
|
275
src/compiler.ts
275
src/compiler.ts
@ -4690,7 +4690,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT);
|
let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT);
|
||||||
let indexedSet = (<Class>target).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
|
let indexedSet = (<Class>target).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
|
||||||
if (!indexedSet) {
|
if (!indexedSet) {
|
||||||
let arrayBufferView = this.program.arrayBufferView;
|
let arrayBufferView = this.program.arrayBufferViewInstance;
|
||||||
if (arrayBufferView) {
|
if (arrayBufferView) {
|
||||||
if ((<Class>target).prototype.extends(arrayBufferView.prototype)) {
|
if ((<Class>target).prototype.extends(arrayBufferView.prototype)) {
|
||||||
return compileArraySet(
|
return compileArraySet(
|
||||||
@ -5910,7 +5910,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
let isUnchecked = this.currentFlow.is(FlowFlags.UNCHECKED_CONTEXT);
|
let isUnchecked = this.currentFlow.is(FlowFlags.UNCHECKED_CONTEXT);
|
||||||
let indexedGet = (<Class>target).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
|
let indexedGet = (<Class>target).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
|
||||||
if (!indexedGet) {
|
if (!indexedGet) {
|
||||||
let arrayBufferView = this.program.arrayBufferView;
|
let arrayBufferView = this.program.arrayBufferViewInstance;
|
||||||
if (arrayBufferView) {
|
if (arrayBufferView) {
|
||||||
if ((<Class>target).prototype.extends(arrayBufferView.prototype)) {
|
if ((<Class>target).prototype.extends(arrayBufferView.prototype)) {
|
||||||
return compileArrayGet(
|
return compileArrayGet(
|
||||||
@ -6427,34 +6427,17 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return this.ensureStaticString(expression.value);
|
return this.ensureStaticString(expression.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ensures that the specified array exists in static memory and returns a pointer to it. */
|
ensureStaticArrayBuffer(elementType: Type, values: ExpressionRef[]): ExpressionRef {
|
||||||
ensureStaticArray(elementType: Type, values: ExpressionRef[]): ExpressionRef {
|
|
||||||
var program = this.program;
|
var program = this.program;
|
||||||
var hasGC = program.hasGC;
|
|
||||||
var gcHeaderSize = program.gcHeaderSize;
|
|
||||||
|
|
||||||
var length = values.length;
|
var length = values.length;
|
||||||
var byteSize = elementType.byteSize;
|
var byteSize = elementType.byteSize;
|
||||||
var byteLength = length * byteSize;
|
var byteLength = length * byteSize;
|
||||||
var usizeTypeSize = this.options.usizeType.byteSize;
|
|
||||||
|
|
||||||
var buf: Uint8Array;
|
|
||||||
var pos: u32;
|
|
||||||
|
|
||||||
// create the backing ArrayBuffer segment
|
|
||||||
var bufferInstance = assert(program.arrayBufferInstance);
|
var bufferInstance = assert(program.arrayBufferInstance);
|
||||||
var bufferHeaderSize = (bufferInstance.currentMemoryOffset + 7) & ~7;
|
var runtimeHeaderSize = program.runtimeHeaderSize;
|
||||||
var bufferTotalSize = 1 << (32 - clz(bufferHeaderSize + byteLength - 1));
|
|
||||||
if (hasGC) {
|
var buf = new Uint8Array(runtimeHeaderSize + byteLength);
|
||||||
buf = new Uint8Array(gcHeaderSize + bufferTotalSize);
|
program.writeRuntimeHeader(buf, 0, bufferInstance, byteLength);
|
||||||
pos = gcHeaderSize;
|
var pos = runtimeHeaderSize;
|
||||||
writeI32(ensureGCHook(this, bufferInstance), buf, program.gcHookOffset);
|
|
||||||
} else {
|
|
||||||
buf = new Uint8Array(bufferTotalSize);
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
writeI32(byteLength, buf, pos + bufferInstance.offsetof(LibrarySymbols.byteLength));
|
|
||||||
pos += bufferHeaderSize;
|
|
||||||
var nativeType = elementType.toNativeType();
|
var nativeType = elementType.toNativeType();
|
||||||
switch (nativeType) {
|
switch (nativeType) {
|
||||||
case NativeType.I32: {
|
case NativeType.I32: {
|
||||||
@ -6525,45 +6508,153 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
var bufferSegment = this.addMemorySegment(buf);
|
assert(pos == buf.length);
|
||||||
var bufferOffset = bufferSegment.offset;
|
|
||||||
if (hasGC) bufferOffset = i64_add(bufferOffset, i64_new(gcHeaderSize));
|
|
||||||
|
|
||||||
// create the Array segment and return a pointer to it
|
var segment = this.addMemorySegment(buf);
|
||||||
var arrayPrototype = assert(program.arrayPrototype);
|
var offset = i64_add(segment.offset, i64_new(runtimeHeaderSize));
|
||||||
var arrayInstance = assert(this.resolver.resolveClass(
|
this.currentType = bufferInstance.type;
|
||||||
arrayPrototype,
|
return program.options.isWasm64
|
||||||
[ elementType ],
|
? this.module.createI64(i64_low(offset), i64_high(offset))
|
||||||
makeMap<string,Type>()
|
: this.module.createI32(i64_low(offset));
|
||||||
));
|
|
||||||
var arrayHeaderSize = (arrayInstance.currentMemoryOffset + 7) & ~7;
|
|
||||||
if (hasGC) {
|
|
||||||
buf = new Uint8Array(gcHeaderSize + arrayHeaderSize);
|
|
||||||
pos = gcHeaderSize;
|
|
||||||
writeI32(ensureGCHook(this, arrayInstance), buf, program.gcHookOffset);
|
|
||||||
} else {
|
|
||||||
buf = new Uint8Array(arrayHeaderSize);
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
var arraySegment = this.addMemorySegment(buf);
|
|
||||||
var arrayOffset = arraySegment.offset;
|
|
||||||
if (hasGC) arrayOffset = i64_add(arrayOffset, i64_new(gcHeaderSize));
|
|
||||||
this.currentType = arrayInstance.type;
|
|
||||||
var buffer_offset = pos + arrayInstance.offsetof("buffer_");
|
|
||||||
var length_offset = pos + arrayInstance.offsetof("length_");
|
|
||||||
if (usizeTypeSize == 8) {
|
|
||||||
writeI64(bufferOffset, buf, buffer_offset);
|
|
||||||
writeI32(length, buf, length_offset);
|
|
||||||
return this.module.createI64(i64_low(arrayOffset), i64_high(arrayOffset));
|
|
||||||
} else {
|
|
||||||
assert(i64_is_u32(bufferOffset));
|
|
||||||
writeI32(i64_low(bufferOffset), buf, buffer_offset);
|
|
||||||
writeI32(length, buf, length_offset);
|
|
||||||
assert(i64_is_u32(arrayOffset));
|
|
||||||
return this.module.createI32(i64_low(arrayOffset));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Ensures that the specified array exists in static memory and returns a pointer to it. */
|
||||||
|
// ensureStaticArray(elementType: Type, values: ExpressionRef[]): ExpressionRef {
|
||||||
|
// var program = this.program;
|
||||||
|
// var hasGC = program.hasGC;
|
||||||
|
// var gcHeaderSize = program.gcHeaderSize;
|
||||||
|
|
||||||
|
// var length = values.length;
|
||||||
|
// var byteSize = elementType.byteSize;
|
||||||
|
// var byteLength = length * byteSize;
|
||||||
|
// var usizeTypeSize = this.options.usizeType.byteSize;
|
||||||
|
|
||||||
|
// var buf: Uint8Array;
|
||||||
|
// var pos: u32;
|
||||||
|
|
||||||
|
// // create the backing ArrayBuffer segment
|
||||||
|
// var bufferInstance = assert(program.arrayBufferInstance);
|
||||||
|
// var bufferHeaderSize = (bufferInstance.currentMemoryOffset + 7) & ~7;
|
||||||
|
// var bufferTotalSize = 1 << (32 - clz(bufferHeaderSize + byteLength - 1));
|
||||||
|
// if (hasGC) {
|
||||||
|
// buf = new Uint8Array(gcHeaderSize + bufferTotalSize);
|
||||||
|
// pos = gcHeaderSize;
|
||||||
|
// writeI32(ensureGCHook(this, bufferInstance), buf, program.gcHookOffset);
|
||||||
|
// } else {
|
||||||
|
// buf = new Uint8Array(bufferTotalSize);
|
||||||
|
// pos = 0;
|
||||||
|
// }
|
||||||
|
// writeI32(byteLength, buf, pos + bufferInstance.offsetof(LibrarySymbols.byteLength));
|
||||||
|
// pos += bufferHeaderSize;
|
||||||
|
// var nativeType = elementType.toNativeType();
|
||||||
|
// switch (nativeType) {
|
||||||
|
// case NativeType.I32: {
|
||||||
|
// switch (byteSize) {
|
||||||
|
// case 1: {
|
||||||
|
// for (let i = 0; i < length; ++i) {
|
||||||
|
// let value = values[i];
|
||||||
|
// assert(getExpressionType(value) == nativeType);
|
||||||
|
// assert(getExpressionId(value) == ExpressionId.Const);
|
||||||
|
// writeI8(getConstValueI32(value), buf, pos);
|
||||||
|
// pos += 1;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case 2: {
|
||||||
|
// for (let i = 0; i < length; ++i) {
|
||||||
|
// let value = values[i];
|
||||||
|
// assert(getExpressionType(value) == nativeType);
|
||||||
|
// assert(getExpressionId(value) == ExpressionId.Const);
|
||||||
|
// writeI16(getConstValueI32(value), buf, pos);
|
||||||
|
// pos += 2;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case 4: {
|
||||||
|
// for (let i = 0; i < length; ++i) {
|
||||||
|
// let value = values[i];
|
||||||
|
// assert(getExpressionType(value) == nativeType);
|
||||||
|
// assert(getExpressionId(value) == ExpressionId.Const);
|
||||||
|
// writeI32(getConstValueI32(value), buf, pos);
|
||||||
|
// pos += 4;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// default: assert(false);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case NativeType.I64: {
|
||||||
|
// for (let i = 0; i < length; ++i) {
|
||||||
|
// let value = values[i];
|
||||||
|
// assert(getExpressionType(value) == nativeType);
|
||||||
|
// assert(getExpressionId(value) == ExpressionId.Const);
|
||||||
|
// writeI64(i64_new(getConstValueI64Low(value), getConstValueI64High(value)), buf, pos);
|
||||||
|
// pos += 8;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case NativeType.F32: {
|
||||||
|
// for (let i = 0; i < length; ++i) {
|
||||||
|
// let value = values[i];
|
||||||
|
// assert(getExpressionType(value) == nativeType);
|
||||||
|
// assert(getExpressionId(value) == ExpressionId.Const);
|
||||||
|
// writeF32(getConstValueF32(value), buf, pos);
|
||||||
|
// pos += 4;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case NativeType.F64: {
|
||||||
|
// for (let i = 0; i < length; ++i) {
|
||||||
|
// let value = values[i];
|
||||||
|
// assert(getExpressionType(value) == nativeType);
|
||||||
|
// assert(getExpressionId(value) == ExpressionId.Const);
|
||||||
|
// writeF64(getConstValueF64(value), buf, pos);
|
||||||
|
// pos += 8;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// default: assert(false);
|
||||||
|
// }
|
||||||
|
// var bufferSegment = this.addMemorySegment(buf);
|
||||||
|
// var bufferOffset = bufferSegment.offset;
|
||||||
|
// if (hasGC) bufferOffset = i64_add(bufferOffset, i64_new(gcHeaderSize));
|
||||||
|
|
||||||
|
// // create the Array segment and return a pointer to it
|
||||||
|
// var arrayPrototype = assert(program.arrayPrototype);
|
||||||
|
// var arrayInstance = assert(this.resolver.resolveClass(
|
||||||
|
// arrayPrototype,
|
||||||
|
// [ elementType ],
|
||||||
|
// makeMap<string,Type>()
|
||||||
|
// ));
|
||||||
|
// var arrayHeaderSize = (arrayInstance.currentMemoryOffset + 7) & ~7;
|
||||||
|
// if (hasGC) {
|
||||||
|
// buf = new Uint8Array(gcHeaderSize + arrayHeaderSize);
|
||||||
|
// pos = gcHeaderSize;
|
||||||
|
// writeI32(ensureGCHook(this, arrayInstance), buf, program.gcHookOffset);
|
||||||
|
// } else {
|
||||||
|
// buf = new Uint8Array(arrayHeaderSize);
|
||||||
|
// pos = 0;
|
||||||
|
// }
|
||||||
|
// var arraySegment = this.addMemorySegment(buf);
|
||||||
|
// var arrayOffset = arraySegment.offset;
|
||||||
|
// if (hasGC) arrayOffset = i64_add(arrayOffset, i64_new(gcHeaderSize));
|
||||||
|
// this.currentType = arrayInstance.type;
|
||||||
|
// var buffer_offset = pos + arrayInstance.offsetof("buffer_");
|
||||||
|
// var length_offset = pos + arrayInstance.offsetof("length_");
|
||||||
|
// if (usizeTypeSize == 8) {
|
||||||
|
// writeI64(bufferOffset, buf, buffer_offset);
|
||||||
|
// writeI32(length, buf, length_offset);
|
||||||
|
// return this.module.createI64(i64_low(arrayOffset), i64_high(arrayOffset));
|
||||||
|
// } else {
|
||||||
|
// assert(i64_is_u32(bufferOffset));
|
||||||
|
// writeI32(i64_low(bufferOffset), buf, buffer_offset);
|
||||||
|
// writeI32(length, buf, length_offset);
|
||||||
|
// assert(i64_is_u32(arrayOffset));
|
||||||
|
// return this.module.createI32(i64_low(arrayOffset));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
compileArrayLiteral(
|
compileArrayLiteral(
|
||||||
elementType: Type,
|
elementType: Type,
|
||||||
expressions: (Expression | null)[],
|
expressions: (Expression | null)[],
|
||||||
@ -6601,18 +6692,20 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a static array if possible
|
|
||||||
// if (isStatic) return this.ensureStaticArray(elementType, constantValues); // TODO
|
|
||||||
|
|
||||||
// otherwise obtain the array type
|
|
||||||
var arrayPrototype = assert(this.program.arrayPrototype);
|
var arrayPrototype = assert(this.program.arrayPrototype);
|
||||||
var arrayInstance = assert(this.resolver.resolveClass(
|
var arrayInstance = assert(this.resolver.resolveClass(
|
||||||
<ClassPrototype>arrayPrototype,
|
<ClassPrototype>arrayPrototype,
|
||||||
[ elementType ],
|
[ elementType ],
|
||||||
makeMap<string,Type>()
|
makeMap()
|
||||||
));
|
));
|
||||||
var arrayType = arrayInstance.type;
|
var arrayType = arrayInstance.type;
|
||||||
|
|
||||||
|
// make a static buffer if possible
|
||||||
|
if (isStatic) {
|
||||||
|
// let bufferPtr = this.ensureStaticArrayBuffer(elementType, constantValues);
|
||||||
|
// TODO: runtime.alloc the array header and make it use a copy of the static buffer
|
||||||
|
}
|
||||||
|
|
||||||
// and compile an explicit instantiation
|
// and compile an explicit instantiation
|
||||||
this.currentType = arrayType;
|
this.currentType = arrayType;
|
||||||
var setter = arrayInstance.lookupOverload(OperatorKind.INDEXED_SET, true);
|
var setter = arrayInstance.lookupOverload(OperatorKind.INDEXED_SET, true);
|
||||||
@ -7851,38 +7944,42 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
assert(classInstance.program == program);
|
assert(classInstance.program == program);
|
||||||
var module = this.module;
|
var module = this.module;
|
||||||
var options = this.options;
|
var options = this.options;
|
||||||
|
var nativeSizeType = options.nativeSizeType;
|
||||||
|
|
||||||
// __gc_allocate(size, markFn)
|
// ALLOCATE(payloadSize)
|
||||||
if (program.hasGC && classInstance.type.isManaged(program)) {
|
var allocateInstance = assert(program.allocateInstance);
|
||||||
let allocateInstance = assert(program.gcAllocateInstance);
|
|
||||||
if (!this.compileFunction(allocateInstance)) return module.createUnreachable();
|
if (!this.compileFunction(allocateInstance)) return module.createUnreachable();
|
||||||
this.currentType = classInstance.type;
|
var alloc = module.createCall(
|
||||||
return module.createCall(
|
|
||||||
allocateInstance.internalName, [
|
|
||||||
options.isWasm64
|
|
||||||
? module.createI64(classInstance.currentMemoryOffset)
|
|
||||||
: module.createI32(classInstance.currentMemoryOffset),
|
|
||||||
module.createI32(
|
|
||||||
ensureGCHook(this, classInstance)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
options.nativeSizeType
|
|
||||||
);
|
|
||||||
|
|
||||||
// memory.allocate(size)
|
|
||||||
} else {
|
|
||||||
let allocateInstance = program.memoryAllocateInstance;
|
|
||||||
if (!allocateInstance || !this.compileFunction(allocateInstance)) return module.createUnreachable();
|
|
||||||
this.currentType = classInstance.type;
|
|
||||||
return module.createCall(
|
|
||||||
allocateInstance.internalName, [
|
allocateInstance.internalName, [
|
||||||
options.isWasm64
|
options.isWasm64
|
||||||
? module.createI64(classInstance.currentMemoryOffset)
|
? module.createI64(classInstance.currentMemoryOffset)
|
||||||
: module.createI32(classInstance.currentMemoryOffset)
|
: module.createI32(classInstance.currentMemoryOffset)
|
||||||
|
// module.createI32(
|
||||||
|
// ensureGCHook(this, classInstance)
|
||||||
|
// )
|
||||||
],
|
],
|
||||||
options.nativeSizeType
|
nativeSizeType
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// REGISTER<T>(ref, classId)
|
||||||
|
if (program.gcImplemented) {
|
||||||
|
let registerInstance = assert(program.gcRegisterInstance);
|
||||||
|
if (!this.compileFunction(registerInstance)) return module.createUnreachable();
|
||||||
|
let tempLocal = this.currentFlow.getAndFreeTempLocal(classInstance.type, false);
|
||||||
|
alloc = module.createBlock(null, [
|
||||||
|
module.createCall(
|
||||||
|
registerInstance.internalName, [
|
||||||
|
module.createTeeLocal(tempLocal.index, alloc),
|
||||||
|
module.createI32(classInstance.id)
|
||||||
|
],
|
||||||
|
NativeType.None
|
||||||
|
),
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType)
|
||||||
|
], nativeSizeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.currentType = classInstance.type;
|
||||||
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Makes the initializers for a class's fields. */
|
/** Makes the initializers for a class's fields. */
|
||||||
|
@ -334,7 +334,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
// runtime references
|
// runtime references
|
||||||
|
|
||||||
/** ArrayBufferView reference. */
|
/** ArrayBufferView reference. */
|
||||||
arrayBufferView: Class | null = null;
|
arrayBufferViewInstance: Class | null = null;
|
||||||
/** ArrayBuffer instance reference. */
|
/** ArrayBuffer instance reference. */
|
||||||
arrayBufferInstance: Class | null = null;
|
arrayBufferInstance: Class | null = null;
|
||||||
/** Array prototype reference. */
|
/** Array prototype reference. */
|
||||||
@ -343,8 +343,12 @@ export class Program extends DiagnosticEmitter {
|
|||||||
stringInstance: Class | null = null;
|
stringInstance: Class | null = null;
|
||||||
/** Abort function reference, if present. */
|
/** Abort function reference, if present. */
|
||||||
abortInstance: Function | null = null;
|
abortInstance: Function | null = null;
|
||||||
/** Memory allocation function. */
|
/** Runtime allocation function. */
|
||||||
memoryAllocateInstance: Function | null = null;
|
allocateInstance: Function | null = null;
|
||||||
|
/** Runtime reallocation function. */
|
||||||
|
reallocateInstance: Function | null = null;
|
||||||
|
/** Runtime discard function. */
|
||||||
|
discardInstance: Function | null = null;
|
||||||
|
|
||||||
/** Next class id. */
|
/** Next class id. */
|
||||||
nextClassId: u32 = 1;
|
nextClassId: u32 = 1;
|
||||||
@ -352,9 +356,11 @@ export class Program extends DiagnosticEmitter {
|
|||||||
// gc integration
|
// gc integration
|
||||||
|
|
||||||
/** Whether a garbage collector is present or not. */
|
/** Whether a garbage collector is present or not. */
|
||||||
hasGC: bool = false;
|
get gcImplemented(): bool {
|
||||||
/** Garbage collector allocation function. */
|
return this.gcRegisterInstance !== null;
|
||||||
gcAllocateInstance: Function | null = null;
|
}
|
||||||
|
/** Garbage collector register function called when an object becomes managed. */
|
||||||
|
gcRegisterInstance: Function | null = null;
|
||||||
/** Garbage collector link function called when a managed object is referenced from a parent. */
|
/** Garbage collector link function called when a managed object is referenced from a parent. */
|
||||||
gcLinkInstance: Function | null = null;
|
gcLinkInstance: Function | null = null;
|
||||||
/** Garbage collector mark function called to on reachable managed objects. */
|
/** Garbage collector mark function called to on reachable managed objects. */
|
||||||
@ -380,7 +386,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
/** Gets the size of a common runtime header. */
|
/** Gets the size of a common runtime header. */
|
||||||
get runtimeHeaderSize(): i32 {
|
get runtimeHeaderSize(): i32 {
|
||||||
return this.hasGC ? 16 : 8;
|
return this.gcImplemented ? 16 : 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Writes a common runtime header to the specified buffer. */
|
/** Writes a common runtime header to the specified buffer. */
|
||||||
@ -767,18 +773,18 @@ export class Program extends DiagnosticEmitter {
|
|||||||
// register global library elements
|
// register global library elements
|
||||||
{
|
{
|
||||||
let element: Element | null;
|
let element: Element | null;
|
||||||
if (element = this.lookupGlobal(LibrarySymbols.String)) {
|
|
||||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
|
||||||
this.stringInstance = resolver.resolveClass(<ClassPrototype>element, null);
|
|
||||||
}
|
|
||||||
if (element = this.lookupGlobal(LibrarySymbols.ArrayBufferView)) {
|
if (element = this.lookupGlobal(LibrarySymbols.ArrayBufferView)) {
|
||||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||||
this.arrayBufferView = resolver.resolveClass(<ClassPrototype>element, null);
|
this.arrayBufferViewInstance = resolver.resolveClass(<ClassPrototype>element, null);
|
||||||
}
|
}
|
||||||
if (element = this.lookupGlobal(LibrarySymbols.ArrayBuffer)) {
|
if (element = this.lookupGlobal(LibrarySymbols.ArrayBuffer)) {
|
||||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||||
this.arrayBufferInstance = resolver.resolveClass(<ClassPrototype>element, null);
|
this.arrayBufferInstance = resolver.resolveClass(<ClassPrototype>element, null);
|
||||||
}
|
}
|
||||||
|
if (element = this.lookupGlobal(LibrarySymbols.String)) {
|
||||||
|
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||||
|
this.stringInstance = resolver.resolveClass(<ClassPrototype>element, null);
|
||||||
|
}
|
||||||
if (element = this.lookupGlobal(LibrarySymbols.Array)) {
|
if (element = this.lookupGlobal(LibrarySymbols.Array)) {
|
||||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||||
this.arrayPrototype = <ClassPrototype>element;
|
this.arrayPrototype = <ClassPrototype>element;
|
||||||
@ -787,59 +793,18 @@ export class Program extends DiagnosticEmitter {
|
|||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
this.abortInstance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
this.abortInstance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
}
|
}
|
||||||
if (element = this.lookupGlobal(LibrarySymbols.memory)) {
|
if (element = this.lookupGlobal(LibrarySymbols.ALLOCATE)) {
|
||||||
if (element = element.lookupInSelf(LibrarySymbols.allocate)) {
|
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
this.memoryAllocateInstance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
this.allocateInstance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
}
|
}
|
||||||
|
if (element = this.lookupGlobal(LibrarySymbols.REALLOCATE)) {
|
||||||
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
|
this.reallocateInstance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
}
|
}
|
||||||
|
if (element = this.lookupGlobal(LibrarySymbols.DISCARD)) {
|
||||||
|
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
|
this.discardInstance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register GC hooks if present
|
|
||||||
// FIXME: think about a better way than globals to model this, maybe a GC namespace that can be
|
|
||||||
// dynamically extended by a concrete implementation but then has `@unsafe` methods that normal
|
|
||||||
// code cannot call without explicitly enabling it with a flag.
|
|
||||||
if (
|
|
||||||
this.elementsByName.has("__gc_allocate") &&
|
|
||||||
this.elementsByName.has("__gc_link") &&
|
|
||||||
this.elementsByName.has("__gc_mark")
|
|
||||||
) {
|
|
||||||
// __gc_allocate(usize, (ref: usize) => void): usize
|
|
||||||
let element = <Element>this.elementsByName.get("__gc_allocate");
|
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
|
||||||
let gcAllocateInstance = assert(this.resolver.resolveFunction(<FunctionPrototype>element, null));
|
|
||||||
let signature = gcAllocateInstance.signature;
|
|
||||||
assert(signature.parameterTypes.length == 2);
|
|
||||||
assert(signature.parameterTypes[0] == this.options.usizeType);
|
|
||||||
assert(signature.parameterTypes[1].signatureReference);
|
|
||||||
assert(signature.returnType == this.options.usizeType);
|
|
||||||
|
|
||||||
// __gc_link(usize, usize): void
|
|
||||||
element = <Element>this.elementsByName.get("__gc_link");
|
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
|
||||||
let gcLinkInstance = assert(this.resolver.resolveFunction(<FunctionPrototype>element, null));
|
|
||||||
signature = gcLinkInstance.signature;
|
|
||||||
assert(signature.parameterTypes.length == 2);
|
|
||||||
assert(signature.parameterTypes[0] == this.options.usizeType);
|
|
||||||
assert(signature.parameterTypes[1] == this.options.usizeType);
|
|
||||||
assert(signature.returnType == Type.void);
|
|
||||||
|
|
||||||
// __gc_mark(usize): void
|
|
||||||
element = <Element>this.elementsByName.get("__gc_mark");
|
|
||||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
|
||||||
let gcMarkInstance = assert(this.resolver.resolveFunction(<FunctionPrototype>element, null));
|
|
||||||
signature = gcMarkInstance.signature;
|
|
||||||
assert(signature.parameterTypes.length == 1);
|
|
||||||
assert(signature.parameterTypes[0] == this.options.usizeType);
|
|
||||||
assert(signature.returnType == Type.void);
|
|
||||||
|
|
||||||
this.gcAllocateInstance = gcAllocateInstance;
|
|
||||||
this.gcLinkInstance = gcLinkInstance;
|
|
||||||
this.gcMarkInstance = gcMarkInstance;
|
|
||||||
let gcHookOffset = 2 * options.usizeType.byteSize; // .next + .prev
|
|
||||||
this.gcHookOffset = gcHookOffset;
|
|
||||||
this.gcHeaderSize = (gcHookOffset + 4 + 7) & ~7; // + .hook index + alignment
|
|
||||||
this.hasGC = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark module exports, i.e. to apply proper wrapping behavior on the boundaries
|
// mark module exports, i.e. to apply proper wrapping behavior on the boundaries
|
||||||
|
@ -147,7 +147,7 @@ export class Type {
|
|||||||
|
|
||||||
/** Tests if this is a managed type that needs GC hooks. */
|
/** Tests if this is a managed type that needs GC hooks. */
|
||||||
isManaged(program: Program): bool {
|
isManaged(program: Program): bool {
|
||||||
if (program.hasGC) {
|
if (program.gcImplemented) {
|
||||||
let classReference = this.classReference;
|
let classReference = this.classReference;
|
||||||
return classReference !== null && !classReference.hasDecorator(DecoratorFlags.UNMANAGED);
|
return classReference !== null && !classReference.hasDecorator(DecoratorFlags.UNMANAGED);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { runtime, ArrayBufferView } from "./runtime";
|
import { ALLOCATE, REALLOCATE, DISCARD, LINK, REGISTER, MAX_BYTELENGTH, ArrayBufferView } from "./runtime";
|
||||||
import { gc } from "./gc";
|
|
||||||
import { ArrayBuffer } from "./arraybuffer";
|
import { ArrayBuffer } from "./arraybuffer";
|
||||||
import { COMPARATOR, SORT } from "./util/sort";
|
import { COMPARATOR, SORT } from "./util/sort";
|
||||||
import { itoa, dtoa, itoa_stream, dtoa_stream, MAX_DOUBLE_LENGTH } from "./util/number";
|
import { itoa, dtoa, itoa_stream, dtoa_stream, MAX_DOUBLE_LENGTH } from "./util/number";
|
||||||
@ -8,7 +7,7 @@ import { isArray as builtin_isArray } from "./builtins";
|
|||||||
export class Array<T> extends ArrayBufferView {
|
export class Array<T> extends ArrayBufferView {
|
||||||
private length_: i32;
|
private length_: i32;
|
||||||
|
|
||||||
@inline static isArray<U>(value: U): bool {
|
static isArray<U>(value: U): bool {
|
||||||
return builtin_isArray(value) && value !== null;
|
return builtin_isArray(value) && value !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +33,10 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
var oldData = this.data;
|
var oldData = this.data;
|
||||||
var oldCapacity = oldData.byteLength >>> alignof<T>();
|
var oldCapacity = oldData.byteLength >>> alignof<T>();
|
||||||
if (<u32>length > <u32>oldCapacity) {
|
if (<u32>length > <u32>oldCapacity) {
|
||||||
const MAX_LENGTH = ArrayBufferView.MAX_BYTELENGTH >>> alignof<T>();
|
const MAX_LENGTH = MAX_BYTELENGTH >>> alignof<T>();
|
||||||
if (<u32>length > <u32>MAX_LENGTH) throw new RangeError("Invalid array length");
|
if (<u32>length > <u32>MAX_LENGTH) throw new RangeError("Invalid array length");
|
||||||
let newCapacity = <usize>length << alignof<T>();
|
let newCapacity = <usize>length << alignof<T>();
|
||||||
let newData = runtime.realloc(changetype<usize>(oldData), newCapacity); // registers on move
|
let newData = REALLOCATE(changetype<usize>(oldData), newCapacity); // registers on move
|
||||||
if (newData !== changetype<usize>(oldData)) {
|
if (newData !== changetype<usize>(oldData)) {
|
||||||
this.data = changetype<ArrayBuffer>(newData); // links
|
this.data = changetype<ArrayBuffer>(newData); // links
|
||||||
this.dataStart = newData;
|
this.dataStart = newData;
|
||||||
@ -77,7 +76,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
private __set(index: i32, value: T): void {
|
private __set(index: i32, value: T): void {
|
||||||
this.resize(index + 1);
|
this.resize(index + 1);
|
||||||
store<T>(this.dataStart + (<usize>index << alignof<T>()), value);
|
store<T>(this.dataStart + (<usize>index << alignof<T>()), value);
|
||||||
if (isManaged<T>()) gc.link(value, this);
|
if (isManaged<T>()) LINK(value, this);
|
||||||
if (index >= this.length_) this.length_ = index + 1;
|
if (index >= this.length_) this.length_ = index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +141,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
this.resize(newLength);
|
this.resize(newLength);
|
||||||
this.length_ = newLength;
|
this.length_ = newLength;
|
||||||
store<T>(this.dataStart + (<usize>(newLength - 1) << alignof<T>()), element);
|
store<T>(this.dataStart + (<usize>(newLength - 1) << alignof<T>()), element);
|
||||||
if (isManaged<T>()) gc.link(element, this);
|
if (isManaged<T>()) LINK(element, this);
|
||||||
return newLength;
|
return newLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,14 +156,14 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
for (let offset: usize = 0; offset < thisSize; offset += sizeof<T>()) {
|
for (let offset: usize = 0; offset < thisSize; offset += sizeof<T>()) {
|
||||||
let element = load<T>(thisStart + offset);
|
let element = load<T>(thisStart + offset);
|
||||||
store<T>(outStart + offset, element);
|
store<T>(outStart + offset, element);
|
||||||
gc.link(element, out);
|
LINK(element, out);
|
||||||
}
|
}
|
||||||
let otherStart = other.dataStart;
|
let otherStart = other.dataStart;
|
||||||
let otherSize = <usize>otherLen << alignof<T>();
|
let otherSize = <usize>otherLen << alignof<T>();
|
||||||
for (let offset: usize = 0; offset < otherSize; offset += sizeof<T>()) {
|
for (let offset: usize = 0; offset < otherSize; offset += sizeof<T>()) {
|
||||||
let element = load<T>(otherStart + offset);
|
let element = load<T>(otherStart + offset);
|
||||||
store<T>(outStart + thisSize + offset, element);
|
store<T>(outStart + thisSize + offset, element);
|
||||||
gc.link(element, out);
|
LINK(element, out);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memory.copy(outStart, this.dataStart, thisSize);
|
memory.copy(outStart, this.dataStart, thisSize);
|
||||||
@ -222,7 +221,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
|
let value = load<T>(this.dataStart + (<usize>index << alignof<T>()));
|
||||||
let result = callbackfn(value, index, this);
|
let result = callbackfn(value, index, this);
|
||||||
store<U>(outStart + (<usize>index << alignof<U>()), result);
|
store<U>(outStart + (<usize>index << alignof<U>()), result);
|
||||||
if (isManaged<U>()) gc.link(result, out);
|
if (isManaged<U>()) LINK(result, out);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -294,7 +293,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
<usize>(newLength - 1) << alignof<T>()
|
<usize>(newLength - 1) << alignof<T>()
|
||||||
);
|
);
|
||||||
store<T>(base, element);
|
store<T>(base, element);
|
||||||
if (isManaged<T>()) gc.link(element, this);
|
if (isManaged<T>()) LINK(element, this);
|
||||||
this.length_ = newLength;
|
this.length_ = newLength;
|
||||||
return newLength;
|
return newLength;
|
||||||
}
|
}
|
||||||
@ -311,7 +310,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
let offset = <usize>i << alignof<T>();
|
let offset = <usize>i << alignof<T>();
|
||||||
let element = load<T>(thisBase + offset);
|
let element = load<T>(thisBase + offset);
|
||||||
store<T>(sliceBase + offset, element);
|
store<T>(sliceBase + offset, element);
|
||||||
if (isManaged<T>()) gc.link(element, slice);
|
if (isManaged<T>()) LINK(element, slice);
|
||||||
}
|
}
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
@ -327,7 +326,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
for (let i = 0; i < deleteCount; ++i) {
|
for (let i = 0; i < deleteCount; ++i) {
|
||||||
let element = load<T>(thisBase + (<usize>i << alignof<T>()));
|
let element = load<T>(thisBase + (<usize>i << alignof<T>()));
|
||||||
store<T>(spliceStart + (<usize>i << alignof<T>()), element);
|
store<T>(spliceStart + (<usize>i << alignof<T>()), element);
|
||||||
if (isManaged<T>()) gc.link(element, splice);
|
if (isManaged<T>()) LINK(element, splice);
|
||||||
}
|
}
|
||||||
memory.copy(
|
memory.copy(
|
||||||
splice.dataStart,
|
splice.dataStart,
|
||||||
@ -397,7 +396,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
var sepLen = separator.length;
|
var sepLen = separator.length;
|
||||||
var valueLen = 5; // max possible length of element len("false")
|
var valueLen = 5; // max possible length of element len("false")
|
||||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
var result = runtime.alloc(estLen << 1);
|
var result = ALLOCATE(estLen << 1);
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var value: bool;
|
var value: bool;
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
@ -429,10 +428,10 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
|
|
||||||
if (estLen > offset) {
|
if (estLen > offset) {
|
||||||
let trimmed = changetype<string>(result).substring(0, offset);
|
let trimmed = changetype<string>(result).substring(0, offset);
|
||||||
runtime.freeUnregistered(result);
|
DISCARD(result);
|
||||||
return trimmed; // registered in .substring
|
return trimmed; // registered in .substring
|
||||||
}
|
}
|
||||||
return gc.register<string>(result);
|
return REGISTER<string>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private join_int(separator: string = ","): string {
|
private join_int(separator: string = ","): string {
|
||||||
@ -445,7 +444,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
var sepLen = separator.length;
|
var sepLen = separator.length;
|
||||||
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + i32(isSigned<T>());
|
const valueLen = (sizeof<T>() <= 4 ? 10 : 20) + i32(isSigned<T>());
|
||||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
var result = runtime.alloc(estLen << 1);
|
var result = ALLOCATE(estLen << 1);
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var value: T;
|
var value: T;
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
@ -466,10 +465,10 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
offset += itoa_stream<T>(result, offset, value);
|
offset += itoa_stream<T>(result, offset, value);
|
||||||
if (estLen > offset) {
|
if (estLen > offset) {
|
||||||
let trimmed = changetype<string>(result).substring(0, offset);
|
let trimmed = changetype<string>(result).substring(0, offset);
|
||||||
runtime.freeUnregistered(result);
|
DISCARD(result);
|
||||||
return trimmed; // registered in .substring
|
return trimmed; // registered in .substring
|
||||||
}
|
}
|
||||||
return gc.register<string>(result);
|
return REGISTER<string>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private join_flt(separator: string = ","): string {
|
private join_flt(separator: string = ","): string {
|
||||||
@ -486,7 +485,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
const valueLen = MAX_DOUBLE_LENGTH;
|
const valueLen = MAX_DOUBLE_LENGTH;
|
||||||
var sepLen = separator.length;
|
var sepLen = separator.length;
|
||||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
var result = runtime.alloc(estLen << 1);
|
var result = ALLOCATE(estLen << 1);
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var value: T;
|
var value: T;
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
@ -511,10 +510,10 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
);
|
);
|
||||||
if (estLen > offset) {
|
if (estLen > offset) {
|
||||||
let trimmed = changetype<string>(result).substring(0, offset);
|
let trimmed = changetype<string>(result).substring(0, offset);
|
||||||
runtime.freeUnregistered(result);
|
DISCARD(result);
|
||||||
return trimmed; // registered in .substring
|
return trimmed; // registered in .substring
|
||||||
}
|
}
|
||||||
return gc.register<string>(result);
|
return REGISTER<string>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private join_str(separator: string = ","): string {
|
private join_str(separator: string = ","): string {
|
||||||
@ -529,7 +528,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
estLen += load<string>(dataStart + (<usize>i << alignof<T>())).length;
|
estLen += load<string>(dataStart + (<usize>i << alignof<T>())).length;
|
||||||
}
|
}
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var result = runtime.alloc((estLen + sepLen * lastIndex) << 1);
|
var result = ALLOCATE((estLen + sepLen * lastIndex) << 1);
|
||||||
var value: String;
|
var value: String;
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
value = load<string>(dataStart + (<usize>i << alignof<T>()));
|
||||||
@ -560,7 +559,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
<usize>valueLen << 1
|
<usize>valueLen << 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return gc.register<string>(result);
|
return REGISTER<string>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private join_arr(separator: string = ","): string {
|
private join_arr(separator: string = ","): string {
|
||||||
@ -597,7 +596,7 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
const valueLen = 15; // max possible length of element len("[object Object]")
|
const valueLen = 15; // max possible length of element len("[object Object]")
|
||||||
var sepLen = separator.length;
|
var sepLen = separator.length;
|
||||||
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
var estLen = (valueLen + sepLen) * lastIndex + valueLen;
|
||||||
var result = runtime.alloc(estLen << 1);
|
var result = ALLOCATE(estLen << 1);
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var value: T;
|
var value: T;
|
||||||
for (let i = 0; i < lastIndex; ++i) {
|
for (let i = 0; i < lastIndex; ++i) {
|
||||||
@ -629,13 +628,12 @@ export class Array<T> extends ArrayBufferView {
|
|||||||
}
|
}
|
||||||
if (estLen > offset) {
|
if (estLen > offset) {
|
||||||
let out = changetype<string>(result).substring(0, offset);
|
let out = changetype<string>(result).substring(0, offset);
|
||||||
runtime.freeUnregistered(result);
|
DISCARD(result);
|
||||||
return out; // registered in .substring
|
return out; // registered in .substring
|
||||||
}
|
}
|
||||||
return gc.register<string>(result);
|
return REGISTER<string>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.join();
|
return this.join();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { runtime, ArrayBufferView } from "./runtime";
|
import { ALLOCATE, REGISTER, HEADER, HEADER_SIZE, MAX_BYTELENGTH } from "./runtime";
|
||||||
import { gc } from "./gc";
|
|
||||||
|
|
||||||
@sealed export class ArrayBuffer {
|
@sealed export class ArrayBuffer {
|
||||||
|
|
||||||
@ -22,24 +21,24 @@ import { gc } from "./gc";
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(length: i32) {
|
constructor(length: i32) {
|
||||||
if (<u32>length > <u32>ArrayBufferView.MAX_BYTELENGTH) throw new RangeError("Invalid array buffer length");
|
if (<u32>length > <u32>MAX_BYTELENGTH) throw new RangeError("Invalid array buffer length");
|
||||||
var buffer = runtime.alloc(<usize>length);
|
var buffer = ALLOCATE(<usize>length);
|
||||||
memory.fill(changetype<usize>(buffer), 0, <usize>length);
|
memory.fill(changetype<usize>(buffer), 0, <usize>length);
|
||||||
return gc.register<ArrayBuffer>(buffer);
|
return REGISTER<ArrayBuffer>(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
get byteLength(): i32 {
|
get byteLength(): i32 {
|
||||||
return changetype<runtime.Header>(changetype<usize>(this) - runtime.Header.SIZE).payloadSize;
|
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
slice(begin: i32 = 0, end: i32 = ArrayBufferView.MAX_BYTELENGTH): ArrayBuffer {
|
slice(begin: i32 = 0, end: i32 = MAX_BYTELENGTH): ArrayBuffer {
|
||||||
var length = this.byteLength;
|
var length = this.byteLength;
|
||||||
begin = begin < 0 ? max(length + begin, 0) : min(begin, length);
|
begin = begin < 0 ? max(length + begin, 0) : min(begin, length);
|
||||||
end = end < 0 ? max(length + end , 0) : min(end , length);
|
end = end < 0 ? max(length + end , 0) : min(end , length);
|
||||||
var outSize = <usize>max(end - begin, 0);
|
var outSize = <usize>max(end - begin, 0);
|
||||||
var out = runtime.alloc(outSize);
|
var out = ALLOCATE(outSize);
|
||||||
memory.copy(out, changetype<usize>(this) + <usize>begin, outSize);
|
memory.copy(out, changetype<usize>(this) + <usize>begin, outSize);
|
||||||
return gc.register<ArrayBuffer>(out);
|
return REGISTER<ArrayBuffer>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
|
@ -9,8 +9,8 @@ const TRACE = false;
|
|||||||
@inline
|
@inline
|
||||||
export const HEADER_SIZE: usize = (offsetof<ManagedObject>() + AL_MASK) & ~AL_MASK;
|
export const HEADER_SIZE: usize = (offsetof<ManagedObject>() + AL_MASK) & ~AL_MASK;
|
||||||
|
|
||||||
|
import { ITERATEROOTS } from "../runtime";
|
||||||
import { AL_MASK, MAX_SIZE_32 } from "../util/allocator";
|
import { AL_MASK, MAX_SIZE_32 } from "../util/allocator";
|
||||||
import { gc } from "../gc";
|
|
||||||
|
|
||||||
/** Collector states. */
|
/** Collector states. */
|
||||||
const enum State {
|
const enum State {
|
||||||
@ -140,7 +140,7 @@ function step(): void {
|
|||||||
}
|
}
|
||||||
case State.IDLE: {
|
case State.IDLE: {
|
||||||
if (TRACE) trace("gc~step/IDLE");
|
if (TRACE) trace("gc~step/IDLE");
|
||||||
gc.iterateRoots(__gc_mark);
|
ITERATEROOTS(__gc_mark);
|
||||||
state = State.MARK;
|
state = State.MARK;
|
||||||
if (TRACE) trace("gc~state = MARK");
|
if (TRACE) trace("gc~state = MARK");
|
||||||
break;
|
break;
|
||||||
@ -161,7 +161,7 @@ function step(): void {
|
|||||||
obj.hookFn(objToRef(obj));
|
obj.hookFn(objToRef(obj));
|
||||||
} else {
|
} else {
|
||||||
if (TRACE) trace("gc~step/MARK finish");
|
if (TRACE) trace("gc~step/MARK finish");
|
||||||
gc.iterateRoots(__gc_mark);
|
ITERATEROOTS(__gc_mark);
|
||||||
obj = iter.next;
|
obj = iter.next;
|
||||||
if (obj === toSpace) {
|
if (obj === toSpace) {
|
||||||
let from = fromSpace;
|
let from = fromSpace;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import { MAX_BYTELENGTH } from "./runtime";
|
||||||
import { ArrayBuffer } from "./arraybuffer";
|
import { ArrayBuffer } from "./arraybuffer";
|
||||||
import { ArrayBufferView } from "./runtime";
|
|
||||||
|
|
||||||
export class DataView {
|
export class DataView {
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ export class DataView {
|
|||||||
byteLength: i32 = i32.MIN_VALUE // FIXME
|
byteLength: i32 = i32.MIN_VALUE // FIXME
|
||||||
) {
|
) {
|
||||||
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; // FIXME
|
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; // FIXME
|
||||||
if (<u32>byteLength > <u32>ArrayBufferView.MAX_BYTELENGTH) throw new RangeError("Invalid byteLength");
|
if (<u32>byteLength > <u32>MAX_BYTELENGTH) throw new RangeError("Invalid byteLength");
|
||||||
if (<u32>byteOffset + byteLength > <u32>buffer.byteLength) throw new RangeError("Invalid length");
|
if (<u32>byteOffset + byteLength > <u32>buffer.byteLength) throw new RangeError("Invalid length");
|
||||||
this.data = buffer; // links
|
this.data = buffer; // links
|
||||||
var dataStart = changetype<usize>(buffer) + <usize>byteOffset;
|
var dataStart = changetype<usize>(buffer) + <usize>byteOffset;
|
||||||
|
@ -1,45 +1,30 @@
|
|||||||
import { runtime } from "./runtime";
|
|
||||||
|
|
||||||
/** Garbage collector interface. */
|
/** Garbage collector interface. */
|
||||||
export namespace gc {
|
export namespace gc {
|
||||||
|
|
||||||
/** Whether the garbage collector interface is implemented. */
|
/** Whether the garbage collector interface is implemented. */
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@lazy
|
@lazy
|
||||||
export const implemented: bool = isDefined(
|
export const IMPLEMENTED: bool = isDefined(
|
||||||
// @ts-ignore: stub
|
// @ts-ignore: stub
|
||||||
__gc_register
|
__gc_register
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Gets the computed unique class id of a class type. */
|
|
||||||
// @ts-ignore: decorator
|
|
||||||
@unsafe @builtin
|
|
||||||
export declare function classId<T>(): u32;
|
|
||||||
|
|
||||||
/** Iterates reference root objects. */
|
|
||||||
// @ts-ignore: decorator
|
|
||||||
@unsafe @builtin
|
|
||||||
export declare function iterateRoots(fn: (ref: usize) => void): void;
|
|
||||||
|
|
||||||
/** Registers a managed object to be tracked by the garbage collector. */
|
/** Registers a managed object to be tracked by the garbage collector. */
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@unsafe @inline
|
@unsafe @inline
|
||||||
export function register<T>(ref: usize): T {
|
export function register(ref: usize): void {
|
||||||
runtime.unrefUnregistered(ref).classId = classId<T>();
|
|
||||||
// @ts-ignore: stub
|
// @ts-ignore: stub
|
||||||
if (isDefined(__gc_register)) __gc_register(ref);
|
if (isDefined(__gc_register)) __gc_register(ref);
|
||||||
return changetype<T>(ref);
|
else ERROR("missing implementation: gc.register");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Links a registered object with the registered object now referencing it. */
|
/** Links a registered object with the registered object now referencing it. */
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@unsafe @inline
|
@unsafe @inline
|
||||||
export function link<T, TParent>(ref: T, parentRef: TParent): void {
|
export function link(ref: usize, parentRef: usize): void {
|
||||||
assert(changetype<usize>(ref) >= HEAP_BASE + runtime.Header.SIZE); // must be a heap object
|
|
||||||
var header = changetype<runtime.Header>(changetype<usize>(ref) - runtime.Header.SIZE);
|
|
||||||
assert(header.classId != runtime.Header.MAGIC && header.gc1 != 0 && header.gc2 != 0); // must be registered
|
|
||||||
// @ts-ignore: stub
|
// @ts-ignore: stub
|
||||||
if (isDefined(__gc_link)) __gc_link(ref, parentRef);
|
if (isDefined(__gc_link)) __gc_link(ref, parentRef);
|
||||||
|
else ERROR("missing implementation: gc.link");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Marks an object as being reachable. */
|
/** Marks an object as being reachable. */
|
||||||
|
30
std/assembly/index.d.ts
vendored
30
std/assembly/index.d.ts
vendored
@ -1515,36 +1515,16 @@ declare function unmanaged(constructor: Function): void;
|
|||||||
declare function sealed(constructor: Function): void;
|
declare function sealed(constructor: Function): void;
|
||||||
|
|
||||||
/** Annotates a method, function or constant global as always inlined. */
|
/** Annotates a method, function or constant global as always inlined. */
|
||||||
declare function inline(
|
declare function inline(...args: any[]): any;
|
||||||
target: any,
|
|
||||||
propertyKey: string,
|
|
||||||
descriptor: TypedPropertyDescriptor<any>
|
|
||||||
): TypedPropertyDescriptor<any> | void;
|
|
||||||
|
|
||||||
/** Annotates a method, function or constant global as unsafe. */
|
/** Annotates a method, function or constant global as unsafe. */
|
||||||
declare function unsafe(
|
declare function unsafe(...args: any[]): any;
|
||||||
target: any,
|
|
||||||
propertyKey: string,
|
|
||||||
descriptor: TypedPropertyDescriptor<any>
|
|
||||||
): TypedPropertyDescriptor<any> | void;
|
|
||||||
|
|
||||||
/** Annotates an explicit external name of a function or global. */
|
/** Annotates an explicit external name of a function or global. */
|
||||||
declare function external(namespace: string, name: string): (
|
declare function external(...args: any[]): any;
|
||||||
target: any,
|
|
||||||
propertyKey: string,
|
|
||||||
descriptor: TypedPropertyDescriptor<any>
|
|
||||||
) => TypedPropertyDescriptor<any> | void;
|
|
||||||
|
|
||||||
/** Annotates a global for lazy compilation. */
|
/** Annotates a global for lazy compilation. */
|
||||||
declare function lazy(
|
declare function lazy(...args: any[]): any;
|
||||||
target: any,
|
|
||||||
propertyKey: string,
|
|
||||||
descriptor: TypedPropertyDescriptor<any>
|
|
||||||
): TypedPropertyDescriptor<any> | void;
|
|
||||||
|
|
||||||
/** Annotates a function as the explicit start function. */
|
/** Annotates a function as the explicit start function. */
|
||||||
declare function start(
|
declare function start(...args: any[]): any;
|
||||||
target: any,
|
|
||||||
propertyKey: string,
|
|
||||||
descriptor: TypedPropertyDescriptor<any>
|
|
||||||
): TypedPropertyDescriptor<any> | void;
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { gc } from "./gc";
|
import { LINK } from "./runtime";
|
||||||
import { HASH } from "./util/hash";
|
import { HASH } from "./util/hash";
|
||||||
|
|
||||||
// A deterministic hash map based on CloseTable from https://github.com/jorendorff/dht
|
// A deterministic hash map based on CloseTable from https://github.com/jorendorff/dht
|
||||||
@ -8,12 +8,12 @@ import { HASH } from "./util/hash";
|
|||||||
const INITIAL_CAPACITY = 4;
|
const INITIAL_CAPACITY = 4;
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@inline const
|
@inline
|
||||||
FILL_FACTOR: f64 = 8 / 3;
|
const FILL_FACTOR: f64 = 8 / 3;
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@inline const
|
@inline
|
||||||
FREE_FACTOR: f64 = 3 / 4;
|
const FREE_FACTOR: f64 = 3 / 4;
|
||||||
|
|
||||||
/** Structure of a map entry. */
|
/** Structure of a map entry. */
|
||||||
@unmanaged class MapEntry<K,V> {
|
@unmanaged class MapEntry<K,V> {
|
||||||
@ -124,8 +124,8 @@ export class Map<K,V> {
|
|||||||
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
|
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
|
||||||
entry.taggedNext = load<usize>(bucketPtrBase);
|
entry.taggedNext = load<usize>(bucketPtrBase);
|
||||||
store<usize>(bucketPtrBase, changetype<usize>(entry));
|
store<usize>(bucketPtrBase, changetype<usize>(entry));
|
||||||
if (isManaged<K>()) gc.link(key, this);
|
if (isManaged<K>()) LINK(key, this);
|
||||||
if (isManaged<V>()) gc.link(value, this);
|
if (isManaged<V>()) LINK(value, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
import { AL_MASK, MAX_SIZE_32 } from "./util/allocator";
|
import { AL_MASK, MAX_SIZE_32 } from "./util/allocator";
|
||||||
import { HEAP_BASE, memory } from "./memory";
|
import { HEAP_BASE, memory } from "./memory";
|
||||||
import { gc } from "./gc";
|
|
||||||
|
|
||||||
/** Common runtime. */
|
/** Whether the memory manager interface is implemented. */
|
||||||
export namespace runtime {
|
// @ts-ignore: decorator, stub
|
||||||
|
@lazy export const MM_IMPLEMENTED: bool = isDefined(__memory_allocate);
|
||||||
|
|
||||||
/** Common runtime header of all objects. */
|
/** Whether the garbage collector interface is implemented. */
|
||||||
@unmanaged export class Header {
|
// @ts-ignore: decorator, stub
|
||||||
|
@lazy export const GC_IMPLEMENTED: bool = isDefined(__gc_register);
|
||||||
/** Size of a runtime header. */
|
|
||||||
// @ts-ignore: decorator
|
|
||||||
@lazy @inline
|
|
||||||
static readonly SIZE: usize = gc.implemented
|
|
||||||
? (offsetof<runtime.Header>( ) + AL_MASK) & ~AL_MASK // full header if GC is present
|
|
||||||
: (offsetof<runtime.Header>("gc1") + AL_MASK) & ~AL_MASK; // half header if GC is absent
|
|
||||||
|
|
||||||
/** Magic value used to validate runtime headers. */
|
|
||||||
// @ts-ignore: decorator
|
|
||||||
@lazy @inline
|
|
||||||
static readonly MAGIC: u32 = 0xA55E4B17;
|
|
||||||
|
|
||||||
|
/** Common runtime header. Each managed object has one. */
|
||||||
|
@unmanaged export class HEADER {
|
||||||
/** Unique id of the respective class or a magic value if not yet registered.*/
|
/** Unique id of the respective class or a magic value if not yet registered.*/
|
||||||
classId: u32;
|
classId: u32;
|
||||||
/** Size of the allocated payload. */
|
/** Size of the allocated payload. */
|
||||||
@ -30,63 +21,77 @@ export namespace runtime {
|
|||||||
gc2: usize; // itcm: prev
|
gc2: usize; // itcm: prev
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that header data and layout isn't quite optimal depending on which allocator one
|
/** Common runtime header size. */
|
||||||
// decides to use, but it's done this way for maximum flexibility. Also remember that the
|
export const HEADER_SIZE: usize = GC_IMPLEMENTED
|
||||||
// runtime will most likely change significantly once reftypes and WASM GC are a thing.
|
? (offsetof<HEADER>( ) + AL_MASK) & ~AL_MASK // full header if GC is present
|
||||||
|
: (offsetof<HEADER>("gc1") + AL_MASK) & ~AL_MASK; // half header if GC is absent
|
||||||
|
|
||||||
|
/** Common runtime header magic. Used to assert registered/unregistered status. */
|
||||||
|
export const HEADER_MAGIC: u32 = 0xA55E4B17;
|
||||||
|
|
||||||
|
/** Gets the computed unique class id of a class type. */
|
||||||
|
// @ts-ignore: decorator
|
||||||
|
@unsafe @builtin
|
||||||
|
export declare function CLASSID<T>(): u32;
|
||||||
|
|
||||||
|
/** Iterates over all root objects of a reference type. */
|
||||||
|
// @ts-ignore: decorator
|
||||||
|
@unsafe @builtin
|
||||||
|
export declare function ITERATEROOTS(fn: (ref: usize) => void): void;
|
||||||
|
|
||||||
/** Adjusts an allocation to actual block size. Primarily targets TLSF. */
|
/** Adjusts an allocation to actual block size. Primarily targets TLSF. */
|
||||||
function adjust(payloadSize: usize): usize {
|
export function ADJUST(payloadSize: usize): usize {
|
||||||
// round up to power of 2, e.g. with HEADER_SIZE=8:
|
// round up to power of 2, e.g. with HEADER_SIZE=8:
|
||||||
// 0 -> 2^3 = 8
|
// 0 -> 2^3 = 8
|
||||||
// 1..8 -> 2^4 = 16
|
// 1..8 -> 2^4 = 16
|
||||||
// 9..24 -> 2^5 = 32
|
// 9..24 -> 2^5 = 32
|
||||||
// ...
|
// ...
|
||||||
// MAX_LENGTH -> 2^30 = 0x40000000 (MAX_SIZE_32)
|
// MAX_LENGTH -> 2^30 = 0x40000000 (MAX_SIZE_32)
|
||||||
return <usize>1 << <usize>(<u32>32 - clz<u32>(payloadSize + Header.SIZE - 1));
|
return <usize>1 << <usize>(<u32>32 - clz<u32>(payloadSize + HEADER_SIZE - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Allocates a new object and returns a pointer to its payload. Does not fill. */
|
/** Allocates a new object and returns a pointer to its payload. Does not fill. */
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@unsafe
|
@unsafe
|
||||||
export function alloc(payloadSize: u32): usize {
|
export function ALLOCATE(payloadSize: usize): usize {
|
||||||
var header = changetype<Header>(memory.allocate(adjust(payloadSize)));
|
var header = changetype<HEADER>(memory.allocate(ADJUST(payloadSize)));
|
||||||
header.classId = Header.MAGIC;
|
header.classId = HEADER_MAGIC;
|
||||||
header.payloadSize = payloadSize;
|
header.payloadSize = payloadSize;
|
||||||
if (gc.implemented) {
|
if (GC_IMPLEMENTED) {
|
||||||
header.gc1 = 0;
|
header.gc1 = 0;
|
||||||
header.gc2 = 0;
|
header.gc2 = 0;
|
||||||
}
|
}
|
||||||
return changetype<usize>(header) + Header.SIZE;
|
return changetype<usize>(header) + HEADER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reallocates an object if necessary. Returns a pointer to its (moved) payload. */
|
/** Reallocates an object if necessary. Returns a pointer to its (moved) payload. */
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@unsafe
|
@unsafe
|
||||||
export function realloc(ref: usize, newPayloadSize: u32): usize {
|
export function REALLOCATE(ref: usize, newPayloadSize: usize): usize {
|
||||||
// Background: When managed objects are allocated these aren't immediately registered with GC
|
// Background: When managed objects are allocated these aren't immediately registered with GC
|
||||||
// but can be used as scratch objects while unregistered. This is useful in situations where
|
// but can be used as scratch objects while unregistered. This is useful in situations where
|
||||||
// the object must be reallocated multiple times because its final size isn't known beforehand,
|
// the object must be reallocated multiple times because its final size isn't known beforehand,
|
||||||
// e.g. in Array#filter, with only the final object making it into GC'ed userland.
|
// e.g. in Array#filter, with only the final object making it into GC'ed userland.
|
||||||
var header = changetype<Header>(ref - Header.SIZE);
|
var header = changetype<HEADER>(ref - HEADER_SIZE);
|
||||||
var payloadSize = header.payloadSize;
|
var payloadSize = header.payloadSize;
|
||||||
if (payloadSize < newPayloadSize) {
|
if (payloadSize < newPayloadSize) {
|
||||||
let newAdjustedSize = adjust(newPayloadSize);
|
let newAdjustedSize = ADJUST(newPayloadSize);
|
||||||
if (select(adjust(payloadSize), 0, ref > HEAP_BASE) < newAdjustedSize) {
|
if (select(ADJUST(payloadSize), 0, ref > HEAP_BASE) < newAdjustedSize) {
|
||||||
// move if the allocation isn't large enough or not a heap object
|
// move if the allocation isn't large enough or not a heap object
|
||||||
let newHeader = changetype<Header>(memory.allocate(newAdjustedSize));
|
let newHeader = changetype<HEADER>(memory.allocate(newAdjustedSize));
|
||||||
newHeader.classId = header.classId;
|
newHeader.classId = header.classId;
|
||||||
if (gc.implemented) {
|
if (GC_IMPLEMENTED) {
|
||||||
newHeader.gc1 = 0;
|
newHeader.gc1 = 0;
|
||||||
newHeader.gc2 = 0;
|
newHeader.gc2 = 0;
|
||||||
}
|
}
|
||||||
let newRef = changetype<usize>(newHeader) + Header.SIZE;
|
let newRef = changetype<usize>(newHeader) + HEADER_SIZE;
|
||||||
memory.copy(newRef, ref, payloadSize);
|
memory.copy(newRef, ref, payloadSize);
|
||||||
memory.fill(newRef + payloadSize, 0, newPayloadSize - payloadSize);
|
memory.fill(newRef + payloadSize, 0, newPayloadSize - payloadSize);
|
||||||
if (header.classId == Header.MAGIC) {
|
if (header.classId == HEADER_MAGIC) {
|
||||||
// free right away if not registered yet
|
// free right away if not registered yet
|
||||||
assert(ref > HEAP_BASE); // static objects aren't scratch objects
|
assert(ref > HEAP_BASE); // static objects aren't scratch objects
|
||||||
memory.free(changetype<usize>(header));
|
memory.free(changetype<usize>(header));
|
||||||
} else if (gc.implemented) {
|
} else if (GC_IMPLEMENTED) {
|
||||||
// if previously registered, register again
|
// if previously registered, register again
|
||||||
// @ts-ignore: stub
|
// @ts-ignore: stub
|
||||||
__gc_register(ref);
|
__gc_register(ref);
|
||||||
@ -105,31 +110,57 @@ export namespace runtime {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
/** Registers a managed object to be tracked by the garbage collector, if present. */
|
||||||
@unsafe
|
|
||||||
export function unrefUnregistered(ref: usize): Header {
|
|
||||||
assert(ref >= HEAP_BASE + Header.SIZE); // must be a heap object
|
|
||||||
var header = changetype<Header>(ref - Header.SIZE);
|
|
||||||
assert(header.classId == Header.MAGIC); // must be unregistered
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Frees an unregistered object that turned out to be unnecessary. */
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@unsafe @inline
|
@unsafe @inline
|
||||||
export function freeUnregistered<T>(ref: T): void {
|
export function REGISTER<T>(ref: usize): T {
|
||||||
memory.free(changetype<usize>(unrefUnregistered(changetype<usize>(ref))));
|
ASSERT_UNREGISTERED(ref);
|
||||||
|
changetype<HEADER>(ref - HEADER_SIZE).classId = CLASSID<T>();
|
||||||
|
// @ts-ignore: stub
|
||||||
|
if (GC_IMPLEMENTED) __gc_register(ref);
|
||||||
|
return changetype<T>(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Links a registered object with the (registered) object now referencing it. */
|
||||||
|
// @ts-ignore: decorator
|
||||||
|
@unsafe @inline
|
||||||
|
export function LINK<T,TParent>(ref: T, parentRef: TParent): void {
|
||||||
|
ASSERT_REGISTERED(changetype<usize>(ref));
|
||||||
|
ASSERT_REGISTERED(changetype<usize>(parentRef));
|
||||||
|
// @ts-ignore: stub
|
||||||
|
if (GC_IMPLEMENTED) __gc_link(changetype<usize>(ref), changetype<usize>(parentRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Discards an unregistered object that turned out to be unnecessary. */
|
||||||
|
// @ts-ignore: decorator
|
||||||
|
export function DISCARD(ref: usize): void {
|
||||||
|
ASSERT_UNREGISTERED(ref);
|
||||||
|
memory.free(changetype<usize>(ref - HEADER_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
/** Asserts that a managed object is still unregistered. */
|
||||||
|
function ASSERT_UNREGISTERED(ref: usize): void {
|
||||||
|
assert(ref > HEAP_BASE); // must be a heap object
|
||||||
|
assert(changetype<HEADER>(ref - HEADER_SIZE).classId == HEADER_MAGIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Asserts that a managed object has already been registered. */
|
||||||
|
function ASSERT_REGISTERED(ref: usize): void {
|
||||||
|
assert(ref > HEAP_BASE); // must be a heap object
|
||||||
|
assert(changetype<HEADER>(ref - HEADER_SIZE).classId != HEADER_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
import { ArrayBuffer } from "./arraybuffer";
|
import { ArrayBuffer } from "./arraybuffer";
|
||||||
|
|
||||||
export abstract class ArrayBufferView {
|
/** Maximum byte length of any buffer. */
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@lazy
|
@lazy
|
||||||
static readonly MAX_BYTELENGTH: i32 = MAX_SIZE_32 - runtime.Header.SIZE;
|
export const MAX_BYTELENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE;
|
||||||
|
|
||||||
|
/** Hard wired ArrayBufferView interface. */
|
||||||
|
export abstract class ArrayBufferView {
|
||||||
[key: number]: number;
|
[key: number]: number;
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@ -145,7 +176,7 @@ export abstract class ArrayBufferView {
|
|||||||
dataEnd: usize;
|
dataEnd: usize;
|
||||||
|
|
||||||
constructor(length: i32, alignLog2: i32) {
|
constructor(length: i32, alignLog2: i32) {
|
||||||
if (<u32>length > <u32>ArrayBufferView.MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length");
|
if (<u32>length > <u32>MAX_BYTELENGTH >>> alignLog2) throw new RangeError("Invalid length");
|
||||||
var buffer = new ArrayBuffer(length << alignLog2);
|
var buffer = new ArrayBuffer(length << alignLog2);
|
||||||
this.data = buffer;
|
this.data = buffer;
|
||||||
this.dataStart = changetype<usize>(buffer);
|
this.dataStart = changetype<usize>(buffer);
|
||||||
@ -161,7 +192,7 @@ export abstract class ArrayBufferView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get length(): i32 {
|
get length(): i32 {
|
||||||
ERROR("missing implementation: [T extends ArrayBufferView]#length");
|
ERROR("missing implementation: subclasses must implement ArrayBufferView#length");
|
||||||
return unreachable();
|
return unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { gc } from "./gc";
|
import { LINK } from "./runtime";
|
||||||
import { HASH } from "./util/hash";
|
import { HASH } from "./util/hash";
|
||||||
|
|
||||||
// A deterministic hash set based on CloseTable from https://github.com/jorendorff/dht
|
// A deterministic hash set based on CloseTable from https://github.com/jorendorff/dht
|
||||||
@ -114,7 +114,7 @@ export class Set<K> {
|
|||||||
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
|
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
|
||||||
entry.taggedNext = load<usize>(bucketPtrBase);
|
entry.taggedNext = load<usize>(bucketPtrBase);
|
||||||
store<usize>(bucketPtrBase, changetype<usize>(entry));
|
store<usize>(bucketPtrBase, changetype<usize>(entry));
|
||||||
if (isManaged<K>()) gc.link(key, this);
|
if (isManaged<K>()) LINK(key, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +1,26 @@
|
|||||||
import { runtime } from "./runtime";
|
import { ALLOCATE, REGISTER, HEADER, HEADER_SIZE } from "./runtime";
|
||||||
import { gc } from "./gc";
|
|
||||||
import { MAX_SIZE_32 } from "./util/allocator";
|
import { MAX_SIZE_32 } from "./util/allocator";
|
||||||
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
|
||||||
|
|
||||||
@sealed export abstract class String {
|
@sealed export abstract class String {
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
@lazy static readonly MAX_LENGTH: i32 = (MAX_SIZE_32 - HEADER_SIZE) >> alignof<u16>();
|
||||||
@lazy
|
|
||||||
static readonly MAX_LENGTH: i32 = (MAX_SIZE_32 - runtime.Header.SIZE) >> alignof<u16>();
|
|
||||||
|
|
||||||
get length(): i32 {
|
get length(): i32 {
|
||||||
return changetype<runtime.Header>(changetype<usize>(this) - runtime.Header.SIZE).payloadSize >> 1;
|
return changetype<HEADER>(changetype<usize>(this) - HEADER_SIZE).payloadSize >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Add and handle second argument
|
// TODO Add and handle second argument
|
||||||
static fromCharCode(code: i32): String {
|
static fromCharCode(code: i32): String {
|
||||||
var out = runtime.alloc(2);
|
var out = ALLOCATE(2);
|
||||||
store<u16>(out, <u16>code);
|
store<u16>(out, <u16>code);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromCodePoint(code: i32): String {
|
static fromCodePoint(code: i32): String {
|
||||||
assert(<u32>code <= 0x10FFFF);
|
assert(<u32>code <= 0x10FFFF);
|
||||||
var sur = code > 0xFFFF;
|
var sur = code > 0xFFFF;
|
||||||
var out = runtime.alloc((i32(sur) + 1) << 1);
|
var out = ALLOCATE((i32(sur) + 1) << 1);
|
||||||
if (!sur) {
|
if (!sur) {
|
||||||
store<u16>(out, <u16>code);
|
store<u16>(out, <u16>code);
|
||||||
} else {
|
} else {
|
||||||
@ -32,15 +29,15 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
let lo: u32 = (code & 0x3FF) + 0xDC00;
|
let lo: u32 = (code & 0x3FF) + 0xDC00;
|
||||||
store<u32>(out, (hi << 16) | lo);
|
store<u32>(out, (hi << 16) | lo);
|
||||||
}
|
}
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@operator("[]") charAt(pos: i32): String {
|
@operator("[]") charAt(pos: i32): String {
|
||||||
assert(this !== null);
|
assert(this !== null);
|
||||||
if (<u32>pos >= <u32>this.length) return changetype<String>("");
|
if (<u32>pos >= <u32>this.length) return changetype<String>("");
|
||||||
var out = runtime.alloc(2);
|
var out = ALLOCATE(2);
|
||||||
store<u16>(out, load<u16>(changetype<usize>(this) + (<usize>pos << 1)));
|
store<u16>(out, load<u16>(changetype<usize>(this) + (<usize>pos << 1)));
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
charCodeAt(pos: i32): i32 {
|
charCodeAt(pos: i32): i32 {
|
||||||
@ -71,10 +68,10 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
var otherSize: isize = other.length << 1;
|
var otherSize: isize = other.length << 1;
|
||||||
var outSize: usize = thisSize + otherSize;
|
var outSize: usize = thisSize + otherSize;
|
||||||
if (outSize == 0) return changetype<String>("");
|
if (outSize == 0) return changetype<String>("");
|
||||||
var out = runtime.alloc(outSize);
|
var out = ALLOCATE(outSize);
|
||||||
memory.copy(out, changetype<usize>(this), thisSize);
|
memory.copy(out, changetype<usize>(this), thisSize);
|
||||||
memory.copy(out + thisSize, changetype<usize>(other), otherSize);
|
memory.copy(out + thisSize, changetype<usize>(other), otherSize);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
endsWith(searchString: String, endPosition: i32 = String.MAX_LENGTH): bool {
|
endsWith(searchString: String, endPosition: i32 = String.MAX_LENGTH): bool {
|
||||||
@ -184,9 +181,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
if (intStart < 0) intStart = max(size + intStart, 0);
|
if (intStart < 0) intStart = max(size + intStart, 0);
|
||||||
var resultLength = min(max(end, 0), size - intStart);
|
var resultLength = min(max(end, 0), size - intStart);
|
||||||
if (resultLength <= 0) return changetype<String>("");
|
if (resultLength <= 0) return changetype<String>("");
|
||||||
var out = runtime.alloc(resultLength << 1);
|
var out = ALLOCATE(resultLength << 1);
|
||||||
memory.copy(out, changetype<usize>(this) + intStart, resultLength);
|
memory.copy(out, changetype<usize>(this) + intStart, resultLength);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
||||||
@ -199,9 +196,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
len = toPos - fromPos;
|
len = toPos - fromPos;
|
||||||
if (!len) return changetype<String>("");
|
if (!len) return changetype<String>("");
|
||||||
if (!fromPos && toPos == this.length << 1) return this;
|
if (!fromPos && toPos == this.length << 1) return this;
|
||||||
var out = runtime.alloc(len);
|
var out = ALLOCATE(len);
|
||||||
memory.copy(out, changetype<usize>(this) + fromPos, len);
|
memory.copy(out, changetype<usize>(this) + fromPos, len);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
trim(): String {
|
trim(): String {
|
||||||
@ -227,9 +224,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
}
|
}
|
||||||
if (!size) return changetype<String>("");
|
if (!size) return changetype<String>("");
|
||||||
if (!start && size == length << 1) return this;
|
if (!start && size == length << 1) return this;
|
||||||
var out = runtime.alloc(size);
|
var out = ALLOCATE(size);
|
||||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline
|
@inline
|
||||||
@ -257,9 +254,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
if (!offset) return this;
|
if (!offset) return this;
|
||||||
size -= offset;
|
size -= offset;
|
||||||
if (!size) return changetype<String>("");
|
if (!size) return changetype<String>("");
|
||||||
var out = runtime.alloc(size);
|
var out = ALLOCATE(size);
|
||||||
memory.copy(out, changetype<usize>(this) + offset, size);
|
memory.copy(out, changetype<usize>(this) + offset, size);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
trimEnd(): String {
|
trimEnd(): String {
|
||||||
@ -276,9 +273,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
}
|
}
|
||||||
if (!size) return changetype<String>("");
|
if (!size) return changetype<String>("");
|
||||||
if (size == originalSize) return this;
|
if (size == originalSize) return this;
|
||||||
var out = runtime.alloc(size);
|
var out = ALLOCATE(size);
|
||||||
memory.copy(out, changetype<usize>(this), size);
|
memory.copy(out, changetype<usize>(this), size);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
padStart(targetLength: i32, padString: string = " "): String {
|
padStart(targetLength: i32, padString: string = " "): String {
|
||||||
@ -288,7 +285,7 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
var padSize = <usize>padString.length << 1;
|
var padSize = <usize>padString.length << 1;
|
||||||
if (targetSize < thisSize || !padSize) return this;
|
if (targetSize < thisSize || !padSize) return this;
|
||||||
var prependSize = targetSize - thisSize;
|
var prependSize = targetSize - thisSize;
|
||||||
var out = runtime.alloc(targetSize);
|
var out = ALLOCATE(targetSize);
|
||||||
if (prependSize > padSize) {
|
if (prependSize > padSize) {
|
||||||
let repeatCount = (prependSize - 2) / padSize;
|
let repeatCount = (prependSize - 2) / padSize;
|
||||||
let restBase = repeatCount * padSize;
|
let restBase = repeatCount * padSize;
|
||||||
@ -299,7 +296,7 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
memory.copy(out, changetype<usize>(padString), prependSize);
|
memory.copy(out, changetype<usize>(padString), prependSize);
|
||||||
}
|
}
|
||||||
memory.copy(out + prependSize, changetype<usize>(this), thisSize);
|
memory.copy(out + prependSize, changetype<usize>(this), thisSize);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
padEnd(targetLength: i32, padString: string = " "): String {
|
padEnd(targetLength: i32, padString: string = " "): String {
|
||||||
@ -309,7 +306,7 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
var padSize = <usize>padString.length << 1;
|
var padSize = <usize>padString.length << 1;
|
||||||
if (targetSize < thisSize || !padSize) return this;
|
if (targetSize < thisSize || !padSize) return this;
|
||||||
var appendSize = targetSize - thisSize;
|
var appendSize = targetSize - thisSize;
|
||||||
var out = runtime.alloc(targetSize);
|
var out = ALLOCATE(targetSize);
|
||||||
memory.copy(out, changetype<usize>(this), thisSize);
|
memory.copy(out, changetype<usize>(this), thisSize);
|
||||||
if (appendSize > padSize) {
|
if (appendSize > padSize) {
|
||||||
let repeatCount = (appendSize - 2) / padSize;
|
let repeatCount = (appendSize - 2) / padSize;
|
||||||
@ -320,7 +317,7 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
} else {
|
} else {
|
||||||
memory.copy(out + thisSize, changetype<usize>(padString), appendSize);
|
memory.copy(out + thisSize, changetype<usize>(padString), appendSize);
|
||||||
}
|
}
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
repeat(count: i32 = 0): String {
|
repeat(count: i32 = 0): String {
|
||||||
@ -334,9 +331,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
|
|
||||||
if (count == 0 || !length) return changetype<String>("");
|
if (count == 0 || !length) return changetype<String>("");
|
||||||
if (count == 1) return this;
|
if (count == 1) return this;
|
||||||
var out = runtime.alloc((length * count) << 1);
|
var out = ALLOCATE((length * count) << 1);
|
||||||
memory.repeat(out, changetype<usize>(this), <usize>length << 1, count);
|
memory.repeat(out, changetype<usize>(this), <usize>length << 1, count);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
slice(beginIndex: i32, endIndex: i32 = i32.MAX_VALUE): String {
|
slice(beginIndex: i32, endIndex: i32 = i32.MAX_VALUE): String {
|
||||||
@ -345,9 +342,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
var end = endIndex < 0 ? max(endIndex + len, 0) : min(endIndex, len);
|
var end = endIndex < 0 ? max(endIndex + len, 0) : min(endIndex, len);
|
||||||
len = end - begin;
|
len = end - begin;
|
||||||
if (len <= 0) return changetype<String>("");
|
if (len <= 0) return changetype<String>("");
|
||||||
var out = runtime.alloc(len << 1);
|
var out = ALLOCATE(len << 1);
|
||||||
memory.copy(out, changetype<usize>(this) + (<usize>begin << 1), <usize>len << 1);
|
memory.copy(out, changetype<usize>(this) + (<usize>begin << 1), <usize>len << 1);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
split(separator: String | null = null, limit: i32 = i32.MAX_VALUE): String[] {
|
split(separator: String | null = null, limit: i32 = i32.MAX_VALUE): String[] {
|
||||||
@ -365,7 +362,7 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
let buffer = unreachable(); // TODO
|
let buffer = unreachable(); // TODO
|
||||||
// let buffer = <ArrayBuffer>result.buffer_;
|
// let buffer = <ArrayBuffer>result.buffer_;
|
||||||
for (let i: isize = 0; i < length; ++i) {
|
for (let i: isize = 0; i < length; ++i) {
|
||||||
let char = runtime.alloc(2);
|
let char = ALLOCATE(2);
|
||||||
store<u16>(
|
store<u16>(
|
||||||
changetype<usize>(char),
|
changetype<usize>(char),
|
||||||
load<u16>(
|
load<u16>(
|
||||||
@ -385,9 +382,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
while ((end = this.indexOf(separator!, start)) != -1) {
|
while ((end = this.indexOf(separator!, start)) != -1) {
|
||||||
let len = end - start;
|
let len = end - start;
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
let out = runtime.alloc(<usize>len << 1);
|
let out = ALLOCATE(<usize>len << 1);
|
||||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||||
result.push(gc.register<String>(out));
|
result.push(REGISTER<String>(out));
|
||||||
} else {
|
} else {
|
||||||
result.push(changetype<String>(""));
|
result.push(changetype<String>(""));
|
||||||
}
|
}
|
||||||
@ -401,9 +398,9 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
}
|
}
|
||||||
var len = length - start;
|
var len = length - start;
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
let out = runtime.alloc(<usize>len << 1);
|
let out = ALLOCATE(<usize>len << 1);
|
||||||
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
memory.copy(out, changetype<usize>(this) + (<usize>start << 1), <usize>len << 1);
|
||||||
result.push(gc.register<String>(out));
|
result.push(REGISTER<String>(out));
|
||||||
} else {
|
} else {
|
||||||
result.push(changetype<String>(""));
|
result.push(changetype<String>(""));
|
||||||
}
|
}
|
||||||
@ -475,10 +472,10 @@ import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./ut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(ptrPos == len);
|
assert(ptrPos == len);
|
||||||
var out = runtime.alloc(bufPos);
|
var out = ALLOCATE(bufPos);
|
||||||
memory.copy(changetype<usize>(out), buf, bufPos);
|
memory.copy(changetype<usize>(out), buf, bufPos);
|
||||||
memory.free(buf);
|
memory.free(buf);
|
||||||
return gc.register<string>(out);
|
return REGISTER<string>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
toUTF8(): usize {
|
toUTF8(): usize {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { runtime, ArrayBufferView } from "./runtime";
|
import { ALLOCATE, REGISTER, LINK, ArrayBufferView } from "./runtime";
|
||||||
import { gc } from "./gc";
|
|
||||||
import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort";
|
import { COMPARATOR, SORT as SORT_IMPL } from "./util/sort";
|
||||||
|
|
||||||
function clampToByte(value: i32): i32 {
|
function clampToByte(value: i32): i32 {
|
||||||
@ -804,11 +803,11 @@ function SUBARRAY<TArray extends ArrayBufferView, T>(
|
|||||||
else begin = min(begin, length);
|
else begin = min(begin, length);
|
||||||
if (end < 0) end = max(length + end, begin);
|
if (end < 0) end = max(length + end, begin);
|
||||||
else end = max(min(end, length), begin);
|
else end = max(min(end, length), begin);
|
||||||
var out = runtime.alloc(offsetof<TArray>());
|
var out = ALLOCATE(offsetof<TArray>());
|
||||||
store<usize>(out, buffer, offsetof<TArray>("buffer"));
|
store<usize>(out, buffer, offsetof<TArray>("buffer"));
|
||||||
store<usize>(out, array.dataStart + (<usize>begin << alignof<T>()) , offsetof<TArray>("dataStart"));
|
store<usize>(out, array.dataStart + (<usize>begin << alignof<T>()) , offsetof<TArray>("dataStart"));
|
||||||
store<usize>(out, array.dataEnd + (<usize>(end - begin) << alignof<T>()), offsetof<TArray>("dataEnd"));
|
store<usize>(out, array.dataEnd + (<usize>(end - begin) << alignof<T>()), offsetof<TArray>("dataEnd"));
|
||||||
gc.link(buffer, gc.register<TArray>(out)); // register first, then link
|
LINK(buffer, REGISTER<TArray>(out)); // register first, then link
|
||||||
return changetype<TArray>(out);
|
return changetype<TArray>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { runtime, ArrayBufferView } from "../runtime";
|
import { ALLOCATE, REGISTER, DISCARD, ArrayBufferView } from "../runtime";
|
||||||
import { gc } from "../gc";
|
|
||||||
import { CharCode } from "./string";
|
import { CharCode } from "./string";
|
||||||
|
|
||||||
// @ts-ignore: decorator
|
// @ts-ignore: decorator
|
||||||
@ -263,10 +262,10 @@ export function utoa32(value: u32): String {
|
|||||||
if (!value) return "0";
|
if (!value) return "0";
|
||||||
|
|
||||||
var decimals = decimalCount32(value);
|
var decimals = decimalCount32(value);
|
||||||
var out = runtime.alloc(decimals << 1);
|
var out = ALLOCATE(decimals << 1);
|
||||||
|
|
||||||
utoa32_core(changetype<usize>(out), value, decimals);
|
utoa32_core(changetype<usize>(out), value, decimals);
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function itoa32(value: i32): String {
|
export function itoa32(value: i32): String {
|
||||||
@ -276,12 +275,12 @@ export function itoa32(value: i32): String {
|
|||||||
if (sign) value = -value;
|
if (sign) value = -value;
|
||||||
|
|
||||||
var decimals = decimalCount32(value) + u32(sign);
|
var decimals = decimalCount32(value) + u32(sign);
|
||||||
var out = runtime.alloc(decimals << 1);
|
var out = ALLOCATE(decimals << 1);
|
||||||
|
|
||||||
utoa32_core(changetype<usize>(out), value, decimals);
|
utoa32_core(changetype<usize>(out), value, decimals);
|
||||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||||
|
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function utoa64(value: u64): String {
|
export function utoa64(value: u64): String {
|
||||||
@ -291,14 +290,14 @@ export function utoa64(value: u64): String {
|
|||||||
if (value <= u32.MAX_VALUE) {
|
if (value <= u32.MAX_VALUE) {
|
||||||
let val32 = <u32>value;
|
let val32 = <u32>value;
|
||||||
let decimals = decimalCount32(val32);
|
let decimals = decimalCount32(val32);
|
||||||
out = runtime.alloc(decimals << 1);
|
out = ALLOCATE(decimals << 1);
|
||||||
utoa32_core(out, val32, decimals);
|
utoa32_core(out, val32, decimals);
|
||||||
} else {
|
} else {
|
||||||
let decimals = decimalCount64(value);
|
let decimals = decimalCount64(value);
|
||||||
out = runtime.alloc(decimals << 1);
|
out = ALLOCATE(decimals << 1);
|
||||||
utoa64_core(changetype<usize>(out), value, decimals);
|
utoa64_core(changetype<usize>(out), value, decimals);
|
||||||
}
|
}
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function itoa64(value: i64): String {
|
export function itoa64(value: i64): String {
|
||||||
@ -311,16 +310,16 @@ export function itoa64(value: i64): String {
|
|||||||
if (<u64>value <= <u64>u32.MAX_VALUE) {
|
if (<u64>value <= <u64>u32.MAX_VALUE) {
|
||||||
let val32 = <u32>value;
|
let val32 = <u32>value;
|
||||||
let decimals = decimalCount32(val32) + u32(sign);
|
let decimals = decimalCount32(val32) + u32(sign);
|
||||||
out = runtime.alloc(decimals << 1);
|
out = ALLOCATE(decimals << 1);
|
||||||
utoa32_core(changetype<usize>(out), val32, decimals);
|
utoa32_core(changetype<usize>(out), val32, decimals);
|
||||||
} else {
|
} else {
|
||||||
let decimals = decimalCount64(value) + u32(sign);
|
let decimals = decimalCount64(value) + u32(sign);
|
||||||
out = runtime.alloc(decimals << 1);
|
out = ALLOCATE(decimals << 1);
|
||||||
utoa64_core(changetype<usize>(out), value, decimals);
|
utoa64_core(changetype<usize>(out), value, decimals);
|
||||||
}
|
}
|
||||||
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
|
||||||
|
|
||||||
return gc.register<String>(out);
|
return REGISTER<String>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function itoa<T extends number>(value: T): String {
|
export function itoa<T extends number>(value: T): String {
|
||||||
@ -625,10 +624,10 @@ export function dtoa(value: f64): String {
|
|||||||
if (isNaN(value)) return "NaN";
|
if (isNaN(value)) return "NaN";
|
||||||
return select<String>("-Infinity", "Infinity", value < 0);
|
return select<String>("-Infinity", "Infinity", value < 0);
|
||||||
}
|
}
|
||||||
var temp = runtime.alloc(MAX_DOUBLE_LENGTH << 1);
|
var temp = ALLOCATE(MAX_DOUBLE_LENGTH << 1);
|
||||||
var length = dtoa_core(temp, value);
|
var length = dtoa_core(temp, value);
|
||||||
var result = changetype<String>(temp).substring(0, length);
|
var result = changetype<String>(temp).substring(0, length);
|
||||||
runtime.freeUnregistered(temp);
|
DISCARD(temp);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,7 +1166,7 @@
|
|||||||
local.get $2
|
local.get $2
|
||||||
call $~lib/allocator/tlsf/Root#use
|
call $~lib/allocator/tlsf/Root#use
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.alloc (; 17 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/runtime/ALLOCATE (; 17 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
||||||
(local $1 i32)
|
(local $1 i32)
|
||||||
i32.const 1
|
i32.const 1
|
||||||
i32.const 32
|
i32.const 32
|
||||||
@ -2536,7 +2536,7 @@
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.realloc (; 22 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
|
(func $~lib/runtime/REALLOCATE (; 22 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
(local $2 i32)
|
(local $2 i32)
|
||||||
(local $3 i32)
|
(local $3 i32)
|
||||||
(local $4 i32)
|
(local $4 i32)
|
||||||
@ -2611,8 +2611,8 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 184
|
i32.const 184
|
||||||
i32.const 87
|
i32.const 92
|
||||||
i32.const 10
|
i32.const 8
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
@ -2641,34 +2641,32 @@
|
|||||||
i32.store offset=4
|
i32.store offset=4
|
||||||
local.get $0
|
local.get $0
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.unrefUnregistered (; 23 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/runtime/ASSERT_UNREGISTERED (; 23 ;) (type $FUNCSIG$vi) (param $0 i32)
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 232
|
i32.const 216
|
||||||
i32.lt_u
|
i32.le_u
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 184
|
i32.const 184
|
||||||
i32.const 111
|
i32.const 145
|
||||||
i32.const 4
|
i32.const 2
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 16
|
i32.const 16
|
||||||
i32.sub
|
i32.sub
|
||||||
local.tee $0
|
|
||||||
i32.load
|
i32.load
|
||||||
i32.const -1520547049
|
i32.const -1520547049
|
||||||
i32.ne
|
i32.ne
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 184
|
i32.const 184
|
||||||
i32.const 113
|
i32.const 146
|
||||||
i32.const 4
|
i32.const 2
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
local.get $0
|
|
||||||
)
|
)
|
||||||
(func $start:std/runtime (; 24 ;) (type $FUNCSIG$v)
|
(func $start:std/runtime (; 24 ;) (type $FUNCSIG$v)
|
||||||
(local $0 i32)
|
(local $0 i32)
|
||||||
@ -2710,7 +2708,7 @@
|
|||||||
else
|
else
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 30
|
i32.const 31
|
||||||
i32.const 2
|
i32.const 2
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2808,7 +2806,7 @@
|
|||||||
f64.const 0
|
f64.const 0
|
||||||
call $~lib/env/trace
|
call $~lib/env/trace
|
||||||
i32.const 1
|
i32.const 1
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref1
|
global.set $std/runtime/ref1
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
i32.const 16
|
i32.const 16
|
||||||
@ -2821,7 +2819,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 45
|
i32.const 46
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2833,7 +2831,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 46
|
i32.const 47
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2842,12 +2840,12 @@
|
|||||||
local.tee $0
|
local.tee $0
|
||||||
local.get $0
|
local.get $0
|
||||||
global.get $std/runtime/barrier1
|
global.get $std/runtime/barrier1
|
||||||
call $~lib/runtime/runtime.realloc
|
call $~lib/runtime/REALLOCATE
|
||||||
i32.ne
|
i32.ne
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 47
|
i32.const 48
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2859,14 +2857,14 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 48
|
i32.const 49
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
call $~lib/runtime/runtime.realloc
|
call $~lib/runtime/REALLOCATE
|
||||||
global.set $std/runtime/ref2
|
global.set $std/runtime/ref2
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/ref2
|
global.get $std/runtime/ref2
|
||||||
@ -2874,7 +2872,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 50
|
i32.const 51
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2890,16 +2888,20 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 52
|
i32.const 53
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/ref2
|
global.get $std/runtime/ref2
|
||||||
call $~lib/runtime/runtime.unrefUnregistered
|
local.tee $0
|
||||||
|
call $~lib/runtime/ASSERT_UNREGISTERED
|
||||||
|
local.get $0
|
||||||
|
i32.const 16
|
||||||
|
i32.sub
|
||||||
call $~lib/memory/memory.free
|
call $~lib/memory/memory.free
|
||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref3
|
global.set $std/runtime/ref3
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/ref3
|
global.get $std/runtime/ref3
|
||||||
@ -2907,17 +2909,20 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 55
|
i32.const 56
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/barrier1
|
global.get $std/runtime/barrier1
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref4
|
global.set $std/runtime/ref4
|
||||||
global.get $std/runtime/ref4
|
global.get $std/runtime/ref4
|
||||||
local.tee $0
|
local.tee $0
|
||||||
call $~lib/runtime/runtime.unrefUnregistered
|
call $~lib/runtime/ASSERT_UNREGISTERED
|
||||||
|
local.get $0
|
||||||
|
i32.const 16
|
||||||
|
i32.sub
|
||||||
i32.const 2
|
i32.const 2
|
||||||
i32.store
|
i32.store
|
||||||
local.get $0
|
local.get $0
|
||||||
@ -2928,7 +2933,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 59
|
i32.const 60
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2944,7 +2949,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 61
|
i32.const 62
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2956,13 +2961,13 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 62
|
i32.const 63
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
i32.const 10
|
i32.const 10
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref5
|
global.set $std/runtime/ref5
|
||||||
global.get $std/runtime/ref5
|
global.get $std/runtime/ref5
|
||||||
i32.const 16
|
i32.const 16
|
||||||
@ -2973,7 +2978,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 65
|
i32.const 66
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -2989,7 +2994,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 66
|
i32.const 67
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import "allocator/tlsf";
|
import "allocator/tlsf";
|
||||||
|
import { CLASSID, ADJUST, ALLOCATE, REALLOCATE, REGISTER, DISCARD, HEADER, HEADER_SIZE, HEADER_MAGIC } from "runtime";
|
||||||
|
|
||||||
var register_ref: usize = 0;
|
var register_ref: usize = 0;
|
||||||
|
|
||||||
@ -19,48 +20,48 @@ var link_parentRef: usize = 0;
|
|||||||
|
|
||||||
class A {}
|
class A {}
|
||||||
class B {}
|
class B {}
|
||||||
assert(gc.classId<A>() != gc.classId<B>());
|
assert(CLASSID<A>() != CLASSID<B>());
|
||||||
|
|
||||||
function isPowerOf2(x: i32): bool {
|
function isPowerOf2(x: i32): bool {
|
||||||
return x != 0 && (x & (x - 1)) == 0;
|
return x != 0 && (x & (x - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(runtime.adjust(0) > 0);
|
assert(ADJUST(0) > 0);
|
||||||
for (let i = 0; i < 9000; ++i) {
|
for (let i = 0; i < 9000; ++i) {
|
||||||
assert(isPowerOf2(runtime.adjust(i)));
|
assert(isPowerOf2(ADJUST(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
var barrier1 = runtime.adjust(0);
|
var barrier1 = ADJUST(0);
|
||||||
var barrier2 = barrier1 + 1;
|
var barrier2 = barrier1 + 1;
|
||||||
while (runtime.adjust(barrier2 + 1) == runtime.adjust(barrier2)) ++barrier2;
|
while (ADJUST(barrier2 + 1) == ADJUST(barrier2)) ++barrier2;
|
||||||
var barrier3 = barrier2 + 1;
|
var barrier3 = barrier2 + 1;
|
||||||
while (runtime.adjust(barrier3 + 1) == runtime.adjust(barrier3)) ++barrier3;
|
while (ADJUST(barrier3 + 1) == ADJUST(barrier3)) ++barrier3;
|
||||||
|
|
||||||
trace("barrier1", 1, barrier1);
|
trace("barrier1", 1, barrier1);
|
||||||
trace("barrier2", 1, barrier2);
|
trace("barrier2", 1, barrier2);
|
||||||
trace("barrier3", 1, barrier3);
|
trace("barrier3", 1, barrier3);
|
||||||
|
|
||||||
var ref1 = runtime.alloc(1);
|
var ref1 = ALLOCATE(1);
|
||||||
var header1 = changetype<runtime.Header>(ref1 - runtime.Header.SIZE);
|
var header1 = changetype<HEADER>(ref1 - HEADER_SIZE);
|
||||||
assert(header1.classId == runtime.Header.MAGIC);
|
assert(header1.classId == HEADER_MAGIC);
|
||||||
assert(header1.payloadSize == 1);
|
assert(header1.payloadSize == 1);
|
||||||
assert(ref1 == runtime.realloc(ref1, barrier1)); // same segment
|
assert(ref1 == REALLOCATE(ref1, barrier1)); // same segment
|
||||||
assert(header1.payloadSize == barrier1);
|
assert(header1.payloadSize == barrier1);
|
||||||
var ref2 = runtime.realloc(ref1, barrier2);
|
var ref2 = REALLOCATE(ref1, barrier2);
|
||||||
assert(ref1 != ref2); // moves
|
assert(ref1 != ref2); // moves
|
||||||
var header2 = changetype<runtime.Header>(ref2 - runtime.Header.SIZE);
|
var header2 = changetype<HEADER>(ref2 - HEADER_SIZE);
|
||||||
assert(header2.payloadSize == barrier2);
|
assert(header2.payloadSize == barrier2);
|
||||||
runtime.freeUnregistered(ref2);
|
DISCARD(ref2);
|
||||||
var ref3 = runtime.alloc(barrier2);
|
var ref3 = ALLOCATE(barrier2);
|
||||||
assert(ref1 == ref3); // reuses space of ref1 (free'd in realloc), ref2 (explicitly free'd)
|
assert(ref1 == ref3); // reuses space of ref1 (free'd in realloc), ref2 (explicitly free'd)
|
||||||
|
|
||||||
var ref4 = runtime.alloc(barrier1);
|
var ref4 = ALLOCATE(barrier1);
|
||||||
gc.register<A>(ref4); // should call __gc_register
|
REGISTER<A>(ref4); // should call __gc_register
|
||||||
assert(register_ref == ref4);
|
assert(register_ref == ref4);
|
||||||
var header4 = changetype<runtime.Header>(register_ref - runtime.Header.SIZE);
|
var header4 = changetype<HEADER>(register_ref - HEADER_SIZE);
|
||||||
assert(header4.classId == gc.classId<A>());
|
assert(header4.classId == CLASSID<A>());
|
||||||
assert(header4.payloadSize == barrier1);
|
assert(header4.payloadSize == barrier1);
|
||||||
|
|
||||||
var ref5 = runtime.alloc(10);
|
var ref5 = ALLOCATE(10);
|
||||||
assert(changetype<ArrayBuffer>(ref5).byteLength == 10);
|
assert(changetype<ArrayBuffer>(ref5).byteLength == 10);
|
||||||
assert(changetype<String>(ref5).length == 5);
|
assert(changetype<String>(ref5).length == 5);
|
||||||
|
@ -36,10 +36,12 @@
|
|||||||
(global $~lib/allocator/tlsf/Root.HL_END i32 (i32.const 2912))
|
(global $~lib/allocator/tlsf/Root.HL_END i32 (i32.const 2912))
|
||||||
(global $~lib/allocator/tlsf/Root.SIZE i32 (i32.const 2916))
|
(global $~lib/allocator/tlsf/Root.SIZE i32 (i32.const 2916))
|
||||||
(global $~lib/allocator/tlsf/ROOT (mut i32) (i32.const 0))
|
(global $~lib/allocator/tlsf/ROOT (mut i32) (i32.const 0))
|
||||||
|
(global $~lib/runtime/GC_IMPLEMENTED i32 (i32.const 1))
|
||||||
|
(global $~lib/runtime/HEADER_SIZE i32 (i32.const 16))
|
||||||
|
(global $~lib/runtime/HEADER_MAGIC i32 (i32.const -1520547049))
|
||||||
(global $std/runtime/register_ref (mut i32) (i32.const 0))
|
(global $std/runtime/register_ref (mut i32) (i32.const 0))
|
||||||
(global $std/runtime/link_ref (mut i32) (i32.const 0))
|
(global $std/runtime/link_ref (mut i32) (i32.const 0))
|
||||||
(global $std/runtime/link_parentRef (mut i32) (i32.const 0))
|
(global $std/runtime/link_parentRef (mut i32) (i32.const 0))
|
||||||
(global $~lib/gc/gc.implemented i32 (i32.const 1))
|
|
||||||
(global $std/runtime/barrier1 (mut i32) (i32.const 0))
|
(global $std/runtime/barrier1 (mut i32) (i32.const 0))
|
||||||
(global $std/runtime/barrier2 (mut i32) (i32.const 0))
|
(global $std/runtime/barrier2 (mut i32) (i32.const 0))
|
||||||
(global $std/runtime/barrier3 (mut i32) (i32.const 0))
|
(global $std/runtime/barrier3 (mut i32) (i32.const 0))
|
||||||
@ -71,11 +73,11 @@
|
|||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.adjust (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/runtime/ADJUST (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
||||||
i32.const 1
|
i32.const 1
|
||||||
i32.const 32
|
i32.const 32
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.add
|
i32.add
|
||||||
i32.const 1
|
i32.const 1
|
||||||
i32.sub
|
i32.sub
|
||||||
@ -1467,14 +1469,14 @@
|
|||||||
end
|
end
|
||||||
return
|
return
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.alloc (; 23 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/runtime/ALLOCATE (; 23 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
||||||
(local $1 i32)
|
(local $1 i32)
|
||||||
local.get $0
|
local.get $0
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
call $~lib/memory/memory.allocate
|
call $~lib/memory/memory.allocate
|
||||||
local.set $1
|
local.set $1
|
||||||
local.get $1
|
local.get $1
|
||||||
i32.const -1520547049
|
global.get $~lib/runtime/HEADER_MAGIC
|
||||||
i32.store
|
i32.store
|
||||||
local.get $1
|
local.get $1
|
||||||
local.get $0
|
local.get $0
|
||||||
@ -1486,7 +1488,7 @@
|
|||||||
i32.const 0
|
i32.const 0
|
||||||
i32.store offset=12
|
i32.store offset=12
|
||||||
local.get $1
|
local.get $1
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.add
|
i32.add
|
||||||
)
|
)
|
||||||
(func $~lib/util/memory/memcpy (; 24 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
|
(func $~lib/util/memory/memcpy (; 24 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
|
||||||
@ -3243,14 +3245,14 @@
|
|||||||
local.get $0
|
local.get $0
|
||||||
global.set $std/runtime/register_ref
|
global.set $std/runtime/register_ref
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.realloc (; 29 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
|
(func $~lib/runtime/REALLOCATE (; 29 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
(local $2 i32)
|
(local $2 i32)
|
||||||
(local $3 i32)
|
(local $3 i32)
|
||||||
(local $4 i32)
|
(local $4 i32)
|
||||||
(local $5 i32)
|
(local $5 i32)
|
||||||
(local $6 i32)
|
(local $6 i32)
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
local.set $2
|
local.set $2
|
||||||
local.get $2
|
local.get $2
|
||||||
@ -3261,10 +3263,10 @@
|
|||||||
i32.lt_u
|
i32.lt_u
|
||||||
if
|
if
|
||||||
local.get $1
|
local.get $1
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
local.set $4
|
local.set $4
|
||||||
local.get $3
|
local.get $3
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
i32.const 0
|
i32.const 0
|
||||||
local.get $0
|
local.get $0
|
||||||
global.get $~lib/memory/HEAP_BASE
|
global.get $~lib/memory/HEAP_BASE
|
||||||
@ -3287,7 +3289,7 @@
|
|||||||
i32.const 0
|
i32.const 0
|
||||||
i32.store offset=12
|
i32.store offset=12
|
||||||
local.get $5
|
local.get $5
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.add
|
i32.add
|
||||||
local.set $6
|
local.set $6
|
||||||
local.get $6
|
local.get $6
|
||||||
@ -3304,7 +3306,7 @@
|
|||||||
call $~lib/memory/memory.fill
|
call $~lib/memory/memory.fill
|
||||||
local.get $2
|
local.get $2
|
||||||
i32.load
|
i32.load
|
||||||
i32.const -1520547049
|
global.get $~lib/runtime/HEADER_MAGIC
|
||||||
i32.eq
|
i32.eq
|
||||||
if
|
if
|
||||||
local.get $0
|
local.get $0
|
||||||
@ -3314,8 +3316,8 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 184
|
i32.const 184
|
||||||
i32.const 87
|
i32.const 92
|
||||||
i32.const 10
|
i32.const 8
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
@ -3347,55 +3349,52 @@
|
|||||||
i32.store offset=4
|
i32.store offset=4
|
||||||
local.get $0
|
local.get $0
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.unrefUnregistered (; 30 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/runtime/ASSERT_UNREGISTERED (; 30 ;) (type $FUNCSIG$vi) (param $0 i32)
|
||||||
(local $1 i32)
|
|
||||||
local.get $0
|
local.get $0
|
||||||
global.get $~lib/memory/HEAP_BASE
|
global.get $~lib/memory/HEAP_BASE
|
||||||
i32.const 16
|
i32.gt_u
|
||||||
i32.add
|
|
||||||
i32.ge_u
|
|
||||||
i32.eqz
|
i32.eqz
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 184
|
i32.const 184
|
||||||
i32.const 111
|
i32.const 145
|
||||||
i32.const 4
|
i32.const 2
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
local.set $1
|
|
||||||
local.get $1
|
|
||||||
i32.load
|
i32.load
|
||||||
i32.const -1520547049
|
global.get $~lib/runtime/HEADER_MAGIC
|
||||||
i32.eq
|
i32.eq
|
||||||
i32.eqz
|
i32.eqz
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 184
|
i32.const 184
|
||||||
i32.const 113
|
i32.const 146
|
||||||
i32.const 4
|
i32.const 2
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
local.get $1
|
|
||||||
)
|
)
|
||||||
(func $~lib/runtime/runtime.freeUnregistered<usize> (; 31 ;) (type $FUNCSIG$vi) (param $0 i32)
|
(func $~lib/runtime/DISCARD (; 31 ;) (type $FUNCSIG$vi) (param $0 i32)
|
||||||
local.get $0
|
local.get $0
|
||||||
call $~lib/runtime/runtime.unrefUnregistered
|
call $~lib/runtime/ASSERT_UNREGISTERED
|
||||||
|
local.get $0
|
||||||
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
|
i32.sub
|
||||||
call $~lib/memory/memory.free
|
call $~lib/memory/memory.free
|
||||||
)
|
)
|
||||||
(func $~lib/arraybuffer/ArrayBuffer#get:byteLength (; 32 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/arraybuffer/ArrayBuffer#get:byteLength (; 32 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
i32.load offset=4
|
i32.load offset=4
|
||||||
)
|
)
|
||||||
(func $~lib/string/String#get:length (; 33 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
(func $~lib/string/String#get:length (; 33 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
||||||
local.get $0
|
local.get $0
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
i32.load offset=4
|
i32.load offset=4
|
||||||
i32.const 1
|
i32.const 1
|
||||||
@ -3411,20 +3410,20 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 22
|
i32.const 23
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.gt_u
|
i32.gt_u
|
||||||
i32.eqz
|
i32.eqz
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 28
|
i32.const 29
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3439,13 +3438,13 @@
|
|||||||
i32.eqz
|
i32.eqz
|
||||||
br_if $break|0
|
br_if $break|0
|
||||||
local.get $0
|
local.get $0
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
call $std/runtime/isPowerOf2
|
call $std/runtime/isPowerOf2
|
||||||
i32.eqz
|
i32.eqz
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 30
|
i32.const 31
|
||||||
i32.const 2
|
i32.const 2
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3460,7 +3459,7 @@
|
|||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
global.set $std/runtime/barrier1
|
global.set $std/runtime/barrier1
|
||||||
global.get $std/runtime/barrier1
|
global.get $std/runtime/barrier1
|
||||||
i32.const 1
|
i32.const 1
|
||||||
@ -3471,9 +3470,9 @@
|
|||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
i32.const 1
|
i32.const 1
|
||||||
i32.add
|
i32.add
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
i32.eq
|
i32.eq
|
||||||
if
|
if
|
||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
@ -3493,9 +3492,9 @@
|
|||||||
global.get $std/runtime/barrier3
|
global.get $std/runtime/barrier3
|
||||||
i32.const 1
|
i32.const 1
|
||||||
i32.add
|
i32.add
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
global.get $std/runtime/barrier3
|
global.get $std/runtime/barrier3
|
||||||
call $~lib/runtime/runtime.adjust
|
call $~lib/runtime/ADJUST
|
||||||
i32.eq
|
i32.eq
|
||||||
if
|
if
|
||||||
global.get $std/runtime/barrier3
|
global.get $std/runtime/barrier3
|
||||||
@ -3534,21 +3533,21 @@
|
|||||||
f64.const 0
|
f64.const 0
|
||||||
call $~lib/env/trace
|
call $~lib/env/trace
|
||||||
i32.const 1
|
i32.const 1
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref1
|
global.set $std/runtime/ref1
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
global.set $std/runtime/header1
|
global.set $std/runtime/header1
|
||||||
global.get $std/runtime/header1
|
global.get $std/runtime/header1
|
||||||
i32.load
|
i32.load
|
||||||
i32.const -1520547049
|
global.get $~lib/runtime/HEADER_MAGIC
|
||||||
i32.eq
|
i32.eq
|
||||||
i32.eqz
|
i32.eqz
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 45
|
i32.const 46
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3561,7 +3560,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 46
|
i32.const 47
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3569,13 +3568,13 @@
|
|||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/barrier1
|
global.get $std/runtime/barrier1
|
||||||
call $~lib/runtime/runtime.realloc
|
call $~lib/runtime/REALLOCATE
|
||||||
i32.eq
|
i32.eq
|
||||||
i32.eqz
|
i32.eqz
|
||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 47
|
i32.const 48
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3588,14 +3587,14 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 48
|
i32.const 49
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
call $~lib/runtime/runtime.realloc
|
call $~lib/runtime/REALLOCATE
|
||||||
global.set $std/runtime/ref2
|
global.set $std/runtime/ref2
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/ref2
|
global.get $std/runtime/ref2
|
||||||
@ -3604,13 +3603,13 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 50
|
i32.const 51
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/ref2
|
global.get $std/runtime/ref2
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
global.set $std/runtime/header2
|
global.set $std/runtime/header2
|
||||||
global.get $std/runtime/header2
|
global.get $std/runtime/header2
|
||||||
@ -3621,15 +3620,15 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 52
|
i32.const 53
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/ref2
|
global.get $std/runtime/ref2
|
||||||
call $~lib/runtime/runtime.freeUnregistered<usize>
|
call $~lib/runtime/DISCARD
|
||||||
global.get $std/runtime/barrier2
|
global.get $std/runtime/barrier2
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref3
|
global.set $std/runtime/ref3
|
||||||
global.get $std/runtime/ref1
|
global.get $std/runtime/ref1
|
||||||
global.get $std/runtime/ref3
|
global.get $std/runtime/ref3
|
||||||
@ -3638,19 +3637,22 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 55
|
i32.const 56
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/barrier1
|
global.get $std/runtime/barrier1
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref4
|
global.set $std/runtime/ref4
|
||||||
block $~lib/gc/gc.register<A>|inlined.0 (result i32)
|
block $~lib/runtime/REGISTER<A>|inlined.0 (result i32)
|
||||||
global.get $std/runtime/ref4
|
global.get $std/runtime/ref4
|
||||||
local.set $0
|
local.set $0
|
||||||
local.get $0
|
local.get $0
|
||||||
call $~lib/runtime/runtime.unrefUnregistered
|
call $~lib/runtime/ASSERT_UNREGISTERED
|
||||||
|
local.get $0
|
||||||
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
|
i32.sub
|
||||||
i32.const 2
|
i32.const 2
|
||||||
i32.store
|
i32.store
|
||||||
local.get $0
|
local.get $0
|
||||||
@ -3665,13 +3667,13 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 59
|
i32.const 60
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
global.get $std/runtime/register_ref
|
global.get $std/runtime/register_ref
|
||||||
i32.const 16
|
global.get $~lib/runtime/HEADER_SIZE
|
||||||
i32.sub
|
i32.sub
|
||||||
global.set $std/runtime/header4
|
global.set $std/runtime/header4
|
||||||
global.get $std/runtime/header4
|
global.get $std/runtime/header4
|
||||||
@ -3682,7 +3684,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 61
|
i32.const 62
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3695,13 +3697,13 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 62
|
i32.const 63
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
end
|
end
|
||||||
i32.const 10
|
i32.const 10
|
||||||
call $~lib/runtime/runtime.alloc
|
call $~lib/runtime/ALLOCATE
|
||||||
global.set $std/runtime/ref5
|
global.set $std/runtime/ref5
|
||||||
global.get $std/runtime/ref5
|
global.get $std/runtime/ref5
|
||||||
call $~lib/arraybuffer/ArrayBuffer#get:byteLength
|
call $~lib/arraybuffer/ArrayBuffer#get:byteLength
|
||||||
@ -3711,7 +3713,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 65
|
i32.const 66
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
@ -3724,7 +3726,7 @@
|
|||||||
if
|
if
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.const 72
|
i32.const 72
|
||||||
i32.const 66
|
i32.const 67
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call $~lib/env/abort
|
call $~lib/env/abort
|
||||||
unreachable
|
unreachable
|
||||||
|
Loading…
x
Reference in New Issue
Block a user