mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-14 15:31:31 +00:00
Polyfill move_memory and set_memory and remove Heap
This commit is contained in:
@ -10,5 +10,5 @@ export const GETTER_PREFIX = "get:";
|
|||||||
export const SETTER_PREFIX = "set:";
|
export const SETTER_PREFIX = "set:";
|
||||||
/** Delimiter used between class names and instance members. */
|
/** Delimiter used between class names and instance members. */
|
||||||
export const INSTANCE_DELIMITER = "#";
|
export const INSTANCE_DELIMITER = "#";
|
||||||
/** Delimited used between class and namespace names and static members. */
|
/** Delimiter used between class and namespace names and static members. */
|
||||||
export const STATIC_DELIMITER = ".";
|
export const STATIC_DELIMITER = ".";
|
||||||
|
@ -14,23 +14,17 @@ for (var key in binaryen)
|
|||||||
if (/^_(?:Binaryen|Relooper)/.test(key))
|
if (/^_(?:Binaryen|Relooper)/.test(key))
|
||||||
globalScope[key] = binaryen[key];
|
globalScope[key] = binaryen[key];
|
||||||
|
|
||||||
// Use Binaryen's heap
|
// Use Binaryen's heap instead of std heap
|
||||||
Object.defineProperties(globalScope["Heap"] = {
|
globalScope["allocate_memory"] = function allocate_memory(size) {
|
||||||
allocate: function allocate(size) {
|
if (!size) return 0; // should be safe in our case
|
||||||
if (!size) return 0; // should be safe in our case
|
return binaryen._malloc(size);
|
||||||
return binaryen._malloc(size);
|
};
|
||||||
},
|
globalScope["free_memory"] = function free_memory(ptr) {
|
||||||
dispose: function dispose(ptr) {
|
if (ptr) binaryen._free(ptr);
|
||||||
if (ptr) binaryen._free(ptr);
|
};
|
||||||
},
|
globalScope["move_memory"] = function move_memory(dest, src, n) {
|
||||||
copy: function copy(dest, src, n) {
|
return binaryen._memmove(dest, src, n);
|
||||||
return binaryen._memcpy(dest, src, n);
|
};
|
||||||
}
|
|
||||||
}, {
|
|
||||||
free: { get: function() { return binaryen.HEAPU8.length; } },
|
|
||||||
used: { get: function() { return 0; } },
|
|
||||||
size: { get: function() { return binaryen.HEAPU8.length; } }
|
|
||||||
});
|
|
||||||
globalScope["store"] = function store(ptr, val) {
|
globalScope["store"] = function store(ptr, val) {
|
||||||
binaryen.HEAPU8[ptr] = val;
|
binaryen.HEAPU8[ptr] = val;
|
||||||
};
|
};
|
||||||
@ -42,11 +36,11 @@ globalScope["load"] = function load(ptr) {
|
|||||||
var Module = require("../module").Module;
|
var Module = require("../module").Module;
|
||||||
Module.prototype.toBinary = function toBinary(bufferSize) {
|
Module.prototype.toBinary = function toBinary(bufferSize) {
|
||||||
if (!bufferSize) bufferSize = 1024 * 1024; // FIXME: see binaryen.js-post.js in Binaryen
|
if (!bufferSize) bufferSize = 1024 * 1024; // FIXME: see binaryen.js-post.js in Binaryen
|
||||||
var ptr = Heap.allocate(bufferSize);
|
var ptr = allocate_memory(bufferSize);
|
||||||
var len = this.write(ptr, bufferSize);
|
var len = this.write(ptr, bufferSize);
|
||||||
var ret = new Uint8Array(len);
|
var ret = new Uint8Array(len);
|
||||||
ret.set(binaryen.HEAPU8.subarray(ptr, ptr + len));
|
ret.set(binaryen.HEAPU8.subarray(ptr, ptr + len));
|
||||||
Heap.dispose(ptr);
|
free_memory(ptr);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
Module.prototype.toText = function toText() {
|
Module.prototype.toText = function toText() {
|
||||||
|
120
src/module.ts
120
src/module.ts
@ -246,7 +246,7 @@ export class Module {
|
|||||||
static create(): Module {
|
static create(): Module {
|
||||||
var module = new Module();
|
var module = new Module();
|
||||||
module.ref = _BinaryenModuleCreate();
|
module.ref = _BinaryenModuleCreate();
|
||||||
module.lit = changetype<BinaryenLiteral>(Heap.allocate(16));
|
module.lit = changetype<BinaryenLiteral>(allocate_memory(16));
|
||||||
module.noEmit = false;
|
module.noEmit = false;
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
@ -256,11 +256,11 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
var module = new Module();
|
var module = new Module();
|
||||||
module.ref = _BinaryenModuleRead(cArr, buffer.length);
|
module.ref = _BinaryenModuleRead(cArr, buffer.length);
|
||||||
module.lit = changetype<BinaryenLiteral>(Heap.allocate(16));
|
module.lit = changetype<BinaryenLiteral>(allocate_memory(16));
|
||||||
module.noEmit = false;
|
module.noEmit = false;
|
||||||
return module;
|
return module;
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(changetype<usize>(cArr));
|
free_memory(changetype<usize>(cArr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,8 +283,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddFunctionType(this.ref, cStr, result, cArr, paramTypes.length);
|
return _BinaryenAddFunctionType(this.ref, cStr, result, cArr, paramTypes.length);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenGetFunctionTypeBySignature(this.ref, result, cArr, paramTypes.length);
|
return _BinaryenGetFunctionTypeBySignature(this.ref, result, cArr, paramTypes.length);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,8 +341,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenHost(this.ref, op, cStr, cArr, operands ? (<ExpressionRef[]>operands).length : 0);
|
return _BinaryenHost(this.ref, op, cStr, cArr, operands ? (<ExpressionRef[]>operands).length : 0);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +362,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenGetGlobal(this.ref, cStr, type);
|
return _BinaryenGetGlobal(this.ref, cStr, type);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenSetGlobal(this.ref, cStr, value);
|
return _BinaryenSetGlobal(this.ref, cStr, value);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,8 +430,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenBlock(this.ref, cStr, cArr, children.length, type);
|
return _BinaryenBlock(this.ref, cStr, cArr, children.length, type);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenBreak(this.ref, cStr, condition, value);
|
return _BinaryenBreak(this.ref, cStr, condition, value);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +456,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenLoop(this.ref, cStr, body);
|
return _BinaryenLoop(this.ref, cStr, body);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,9 +490,9 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenSwitch(this.ref, cArr, k, cStr, condition, value);
|
return _BinaryenSwitch(this.ref, cArr, k, cStr, condition, value);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
for (i = k - 1; i >= 0; --i) Heap.dispose(strs[i]);
|
for (i = k - 1; i >= 0; --i) free_memory(strs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,8 +503,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType);
|
return _BinaryenCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,8 +515,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenCallImport(this.ref, cStr, cArr, operands && operands.length || 0, returnType);
|
return _BinaryenCallImport(this.ref, cStr, cArr, operands && operands.length || 0, returnType);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,7 +533,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddGlobal(this.ref, cStr, type, mutable ? 1 : 0, initializer);
|
return _BinaryenAddGlobal(this.ref, cStr, type, mutable ? 1 : 0, initializer);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,8 +544,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddFunction(this.ref, cStr, type, cArr, varTypes.length, body);
|
return _BinaryenAddFunction(this.ref, cStr, type, cArr, varTypes.length, body);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,7 +554,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
_BinaryenRemoveFunction(this.ref, cStr);
|
_BinaryenRemoveFunction(this.ref, cStr);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,8 +565,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddFunctionExport(this.ref, cStr1, cStr2);
|
return _BinaryenAddFunctionExport(this.ref, cStr1, cStr2);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,8 +577,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddTableExport(this.ref, cStr1, cStr2);
|
return _BinaryenAddTableExport(this.ref, cStr1, cStr2);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,8 +589,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddMemoryExport(this.ref, cStr1, cStr2);
|
return _BinaryenAddMemoryExport(this.ref, cStr1, cStr2);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,8 +601,8 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddGlobalExport(this.ref, cStr1, cStr2);
|
return _BinaryenAddGlobalExport(this.ref, cStr1, cStr2);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +612,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
_BinaryenRemoveExport(this.ref, cStr);
|
_BinaryenRemoveExport(this.ref, cStr);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,9 +624,9 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddFunctionImport(this.ref, cStr1, cStr2, cStr3, functionType);
|
return _BinaryenAddFunctionImport(this.ref, cStr1, cStr2, cStr3, functionType);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr3);
|
free_memory(cStr3);
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,9 +638,9 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddTableImport(this.ref, cStr1, cStr2, cStr3);
|
return _BinaryenAddTableImport(this.ref, cStr1, cStr2, cStr3);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr3);
|
free_memory(cStr3);
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,9 +652,9 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddMemoryImport(this.ref, cStr1, cStr2, cStr3);
|
return _BinaryenAddMemoryImport(this.ref, cStr1, cStr2, cStr3);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr3);
|
free_memory(cStr3);
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,9 +666,9 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
return _BinaryenAddGlobalImport(this.ref, cStr1, cStr2, cStr3, globalType);
|
return _BinaryenAddGlobalImport(this.ref, cStr1, cStr2, cStr3, globalType);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr3);
|
free_memory(cStr3);
|
||||||
Heap.dispose(cStr2);
|
free_memory(cStr2);
|
||||||
Heap.dispose(cStr1);
|
free_memory(cStr1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +678,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
_BinaryenRemoveImport(this.ref, cStr);
|
_BinaryenRemoveImport(this.ref, cStr);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,11 +704,11 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
_BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, k);
|
_BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, k);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr3);
|
free_memory(cArr3);
|
||||||
Heap.dispose(cArr2);
|
free_memory(cArr2);
|
||||||
Heap.dispose(cArr1);
|
free_memory(cArr1);
|
||||||
for (i = k - 1; i >= 0; --i) Heap.dispose(segs[i]);
|
for (i = k - 1; i >= 0; --i) free_memory(segs[i]);
|
||||||
Heap.dispose(cStr);
|
free_memory(cStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,7 +718,7 @@ export class Module {
|
|||||||
try {
|
try {
|
||||||
_BinaryenSetFunctionTable(this.ref, cArr, funcs.length);
|
_BinaryenSetFunctionTable(this.ref, cArr, funcs.length);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,8 +749,8 @@ export class Module {
|
|||||||
else
|
else
|
||||||
_BinaryenModuleRunPasses(this.ref, cArr, k);
|
_BinaryenModuleRunPasses(this.ref, cArr, k);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
for (; i >= 0; --i) Heap.dispose(names[i]);
|
for (; i >= 0; --i) free_memory(names[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +788,7 @@ export class Module {
|
|||||||
dispose(): void {
|
dispose(): void {
|
||||||
if (!this.ref) return; // sic
|
if (!this.ref) return; // sic
|
||||||
_BinaryenModuleDispose(this.ref);
|
_BinaryenModuleDispose(this.ref);
|
||||||
Heap.dispose(changetype<usize>(this.lit));
|
free_memory(changetype<usize>(this.lit));
|
||||||
}
|
}
|
||||||
|
|
||||||
createRelooper(): Relooper {
|
createRelooper(): Relooper {
|
||||||
@ -890,7 +890,7 @@ export class Relooper {
|
|||||||
try {
|
try {
|
||||||
_RelooperAddBranchForSwitch(from, to, cArr, indexes.length, code);
|
_RelooperAddBranchForSwitch(from, to, cArr, indexes.length, code);
|
||||||
} finally {
|
} finally {
|
||||||
Heap.dispose(cArr);
|
free_memory(cArr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,7 +905,7 @@ export class Relooper {
|
|||||||
|
|
||||||
function allocU8Array(u8s: Uint8Array | null): usize {
|
function allocU8Array(u8s: Uint8Array | null): usize {
|
||||||
if (!u8s) return 0;
|
if (!u8s) return 0;
|
||||||
var ptr = Heap.allocate(u8s.length);
|
var ptr = allocate_memory(u8s.length);
|
||||||
var idx = ptr;
|
var idx = ptr;
|
||||||
for (var i = 0, k = u8s.length; i < k; ++i)
|
for (var i = 0, k = u8s.length; i < k; ++i)
|
||||||
store<u8>(idx++, u8s[i]);
|
store<u8>(idx++, u8s[i]);
|
||||||
@ -914,7 +914,7 @@ function allocU8Array(u8s: Uint8Array | null): usize {
|
|||||||
|
|
||||||
function allocI32Array(i32s: i32[] | null): usize {
|
function allocI32Array(i32s: i32[] | null): usize {
|
||||||
if (!i32s) return 0;
|
if (!i32s) return 0;
|
||||||
var ptr = Heap.allocate(i32s.length << 2);
|
var ptr = allocate_memory(i32s.length << 2);
|
||||||
var idx = ptr;
|
var idx = ptr;
|
||||||
for (var i = 0, k = i32s.length; i < k; ++i) {
|
for (var i = 0, k = i32s.length; i < k; ++i) {
|
||||||
var val = i32s[i];
|
var val = i32s[i];
|
||||||
@ -952,7 +952,7 @@ function stringLengthUTF8(str: string): usize {
|
|||||||
|
|
||||||
function allocString(str: string | null): usize {
|
function allocString(str: string | null): usize {
|
||||||
if (str == null) return 0;
|
if (str == null) return 0;
|
||||||
var ptr = Heap.allocate(stringLengthUTF8(str) + 1);
|
var ptr = allocate_memory(stringLengthUTF8(str) + 1);
|
||||||
var idx = ptr;
|
var idx = ptr;
|
||||||
for (var i = 0, k = str.length; i < k; ++i) {
|
for (var i = 0, k = str.length; i < k; ++i) {
|
||||||
var u = str.charCodeAt(i);
|
var u = str.charCodeAt(i);
|
||||||
|
40
std/assembly.d.ts
vendored
40
std/assembly.d.ts
vendored
@ -162,6 +162,16 @@ declare function store<T>(offset: usize, value: T): void;
|
|||||||
declare function current_memory(): i32;
|
declare function current_memory(): i32;
|
||||||
/** Grows linear memory by a given unsigned delta of pages. One page is 64kb. Returns the previous memory size in units of pages or `-1` on failure. */
|
/** Grows linear memory by a given unsigned delta of pages. One page is 64kb. Returns the previous memory size in units of pages or `-1` on failure. */
|
||||||
declare function grow_memory(value: i32): i32;
|
declare function grow_memory(value: i32): i32;
|
||||||
|
/** Copies n bytes from the specified source to the specified destination in memory. These regions may overlap. */
|
||||||
|
declare function move_memory(destination: usize, source: usize, n: usize): void;
|
||||||
|
/** Sets n bytes beginning at the specified destination in memory to the specified byte value. */
|
||||||
|
declare function set_memory(destination: usize, value: u8, count: usize): void;
|
||||||
|
/** Compares two chunks of memory. Returns `0` if equal, otherwise the difference of the first differing bytes. */
|
||||||
|
declare function compare_memory(vl: usize, vr: usize, n: usize): i32;
|
||||||
|
/** Allocates a chunk of memory of the specified size and returns a pointer to it. */
|
||||||
|
declare function allocate_memory(size: usize): usize;
|
||||||
|
/** Disposes a chunk of memory by its pointer. */
|
||||||
|
declare function free_memory(ptr: usize): void;
|
||||||
/** Emits an unreachable operation that results in a runtime error when executed. Both a statement and an expression of any type. */
|
/** Emits an unreachable operation that results in a runtime error when executed. Both a statement and an expression of any type. */
|
||||||
declare function unreachable(): any; // sic
|
declare function unreachable(): any; // sic
|
||||||
|
|
||||||
@ -250,36 +260,6 @@ declare class Error {
|
|||||||
/** Class for indicating an error when a value is not in the set or range of allowed values. */
|
/** Class for indicating an error when a value is not in the set or range of allowed values. */
|
||||||
declare class RangeError extends Error { }
|
declare class RangeError extends Error { }
|
||||||
|
|
||||||
/** A static class representing the heap. */
|
|
||||||
declare class Heap {
|
|
||||||
|
|
||||||
/** Gets the amount of used heap space, in bytes. */
|
|
||||||
static readonly used: usize;
|
|
||||||
|
|
||||||
/** Gets the amount of free heap space, in bytes. */
|
|
||||||
static readonly free: usize;
|
|
||||||
|
|
||||||
/** Gets the size of the heap, in bytes. */
|
|
||||||
static readonly size: usize;
|
|
||||||
|
|
||||||
/** Allocates a chunk of memory and returns a pointer to it. */
|
|
||||||
static allocate(size: usize): usize;
|
|
||||||
|
|
||||||
/** Disposes a chunk of memory by its pointer. */
|
|
||||||
static dispose(ptr: usize): void;
|
|
||||||
|
|
||||||
/** Copies a chunk of memory from one location to another. */
|
|
||||||
static copy(dest: usize, src: usize, n: usize): usize;
|
|
||||||
|
|
||||||
/** Fills a chunk of memory with the specified byte value. */
|
|
||||||
static fill(dest: usize, c: u8, n: usize): usize;
|
|
||||||
|
|
||||||
/** Compares two chunks of memory. Returns `0` if equal, otherwise the difference of the first differing bytes. */
|
|
||||||
static compare(vl: usize, vr: usize, n: usize): i32;
|
|
||||||
|
|
||||||
private constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Boolean {}
|
interface Boolean {}
|
||||||
interface Function {}
|
interface Function {}
|
||||||
interface IArguments {}
|
interface IArguments {}
|
||||||
|
@ -8,7 +8,7 @@ export class Array<T> {
|
|||||||
if (capacity < 0)
|
if (capacity < 0)
|
||||||
throw new RangeError("invalid array length");
|
throw new RangeError("invalid array length");
|
||||||
this.__capacity = this.length = capacity;
|
this.__capacity = this.length = capacity;
|
||||||
this.__memory = capacity > 0 ? Heap.allocate(<usize>capacity * sizeof<T>()) : 0;
|
this.__memory = capacity > 0 ? allocate_memory(<usize>capacity * sizeof<T>()) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@operator("[]")
|
@operator("[]")
|
||||||
@ -34,19 +34,20 @@ export class Array<T> {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private __grow(capacity: i32): void {
|
private __grow(newCapacity: i32): void {
|
||||||
assert(capacity > this.__capacity);
|
assert(newCapacity > this.__capacity);
|
||||||
var newMemory = Heap.allocate(<usize>(capacity * sizeof<T>()));
|
var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
|
||||||
if (this.__memory)
|
if (this.__memory) {
|
||||||
Heap.copy(newMemory, this.__memory, this.__capacity * sizeof<T>());
|
move_memory(newMemory, this.__memory, this.__capacity * sizeof<T>());
|
||||||
Heap.dispose(this.__memory);
|
free_memory(this.__memory);
|
||||||
|
}
|
||||||
this.__memory = newMemory;
|
this.__memory = newMemory;
|
||||||
this.__capacity = capacity;
|
this.__capacity = newCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
push(element: T): i32 {
|
push(element: T): i32 {
|
||||||
if (<u32>this.length >= this.__capacity)
|
if (<u32>this.length >= this.__capacity)
|
||||||
this.__grow(max(this.length + 1, this.__capacity * 2));
|
this.__grow(max(this.length + 1, this.__capacity << 1));
|
||||||
store<T>(this.__memory + <usize>this.length * sizeof<T>(), element);
|
store<T>(this.__memory + <usize>this.length * sizeof<T>(), element);
|
||||||
return ++this.length;
|
return ++this.length;
|
||||||
}
|
}
|
||||||
@ -62,23 +63,22 @@ export class Array<T> {
|
|||||||
if (this.length < 1 || <u32>this.length > this.__capacity)
|
if (this.length < 1 || <u32>this.length > this.__capacity)
|
||||||
throw new RangeError("index out of range");
|
throw new RangeError("index out of range");
|
||||||
var element = load<T>(this.__memory);
|
var element = load<T>(this.__memory);
|
||||||
Heap.copy(this.__memory, this.__memory + sizeof<T>(), (this.__capacity - 1) * sizeof<T>());
|
move_memory(this.__memory, this.__memory + sizeof<T>(), (this.__capacity - 1) * sizeof<T>());
|
||||||
Heap.fill(this.__memory + (this.__capacity - 1) * sizeof<T>(), 0, sizeof<T>());
|
set_memory(this.__memory + (this.__capacity - 1) * sizeof<T>(), 0, sizeof<T>());
|
||||||
--this.length;
|
--this.length;
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
unshift(element: T): i32 {
|
unshift(element: T): i32 {
|
||||||
var capacity = this.__capacity;
|
var oldCapacity = this.__capacity;
|
||||||
if (<u32>this.length >= capacity)
|
if (<u32>this.length >= oldCapacity)
|
||||||
this.__grow(max(this.length + 1, capacity * 2));
|
this.__grow(max(this.length + 1, oldCapacity * 2));
|
||||||
|
|
||||||
// FIXME: needs memmove (Heap.copy is just memcpy). it's also inefficient because
|
// FIXME: this is inefficient because of two copies, one in __grow and one here
|
||||||
// __grow copies and then unshift copies again.
|
// move_memory(this.__memory + sizeof<T>(), this.__memory, oldCapacity * sizeof<T>());
|
||||||
// Heap.copy(this.__memory + sizeof<T>(), this.__memory, capacity * sizeof<T>());
|
|
||||||
|
|
||||||
if (capacity)
|
if (oldCapacity)
|
||||||
for (var index: usize = capacity; index > 0; --index)
|
for (var index: usize = oldCapacity; index > 0; --index)
|
||||||
store<T>(this.__memory + index * sizeof<T>(), load<T>(this.__memory + (index - 1) * sizeof<T>()));
|
store<T>(this.__memory + index * sizeof<T>(), load<T>(this.__memory + (index - 1) * sizeof<T>()));
|
||||||
|
|
||||||
store<T>(this.__memory, element);
|
store<T>(this.__memory, element);
|
||||||
@ -92,12 +92,16 @@ export class CArray<T> {
|
|||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
@operator("[]")
|
@operator("[]")
|
||||||
private __get(index: usize): T {
|
private __get(index: i32): T {
|
||||||
return load<T>(changetype<usize>(this) + index * sizeof<T>());
|
if (index < 0)
|
||||||
|
throw new RangeError("index out of range");
|
||||||
|
return load<T>(changetype<usize>(this) + <usize>index * sizeof<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@operator("[]=")
|
@operator("[]=")
|
||||||
private __set(index: usize, value: T): void {
|
private __set(index: i32, value: T): void {
|
||||||
store<T>(changetype<usize>(this) + index * sizeof<T>(), value);
|
if (index < 0)
|
||||||
|
throw new RangeError("index out of range");
|
||||||
|
store<T>(changetype<usize>(this) + <usize>index * sizeof<T>(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,245 +4,289 @@ const ALIGN_MASK: usize = ALIGN_SIZE - 1;
|
|||||||
|
|
||||||
var HEAP_OFFSET: usize = HEAP_BASE; // HEAP_BASE is a constant generated by the compiler
|
var HEAP_OFFSET: usize = HEAP_BASE; // HEAP_BASE is a constant generated by the compiler
|
||||||
|
|
||||||
// TODO: maybe tlsf
|
export function allocate_memory(size: usize): usize {
|
||||||
|
if (!size) return 0;
|
||||||
|
var len: i32 = current_memory();
|
||||||
|
if (HEAP_OFFSET + size > <usize>len << 16)
|
||||||
|
if(grow_memory(max<i32>(<i32>ceil<f64>(<f64>size / 65536), len * 2 - len)) < 0)
|
||||||
|
unreachable();
|
||||||
|
var ptr: usize = HEAP_OFFSET;
|
||||||
|
if ((HEAP_OFFSET += size) & ALIGN_MASK) // align next offset
|
||||||
|
HEAP_OFFSET = (HEAP_OFFSET | ALIGN_MASK) + 1;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
export class Heap {
|
export function free_memory(ptr: usize): void {
|
||||||
|
// just a big chunk of non-disposable memory for now
|
||||||
|
}
|
||||||
|
|
||||||
static get used(): usize { return HEAP_OFFSET - HEAP_BASE; }
|
function copy_memory(dest: usize, src: usize, n: usize): void {
|
||||||
static get free(): usize { return (<usize>current_memory() << 16) - HEAP_OFFSET; }
|
// based on musl's implementation of memcpy
|
||||||
static get size(): usize { return (<usize>current_memory() << 16) - HEAP_BASE; }
|
// not a future instruction and sufficiently covered by the upcoming move_memory intrinsic
|
||||||
|
|
||||||
static allocate(size: usize): usize {
|
var w: u32, x: u32;
|
||||||
if (!size) return 0;
|
|
||||||
var len: i32 = current_memory();
|
// copy 1 byte each until src is aligned to 4 bytes
|
||||||
if (HEAP_OFFSET + size > <usize>len << 16)
|
while (n && src % 4) {
|
||||||
if(grow_memory(max<i32>(<i32>ceil<f64>(<f64>size / 65536), len * 2 - len)) < 0)
|
store<u8>(dest++, load<u8>(src++));
|
||||||
unreachable();
|
n--;
|
||||||
var ptr: usize = HEAP_OFFSET;
|
|
||||||
if ((HEAP_OFFSET += size) & ALIGN_MASK) // align next offset
|
|
||||||
HEAP_OFFSET = (HEAP_OFFSET | ALIGN_MASK) + 1;
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static dispose(ptr: usize): void {
|
// if dst is aligned to 4 bytes as well, copy 4 bytes each
|
||||||
// just a big chunk of non-disposable memory for now
|
if (dest % 4 == 0) {
|
||||||
}
|
while (n >= 16) {
|
||||||
|
store<u32>(dest , load<u32>(src ));
|
||||||
static copy(dest: usize, src: usize, n: usize): usize { // TODO: use move_memory op once available
|
store<u32>(dest + 4, load<u32>(src + 4));
|
||||||
assert(dest >= HEAP_BASE);
|
store<u32>(dest + 8, load<u32>(src + 8));
|
||||||
|
store<u32>(dest + 12, load<u32>(src + 12));
|
||||||
// the following is based on musl's implementation of memcpy
|
src += 16; dest += 16; n -= 16;
|
||||||
var dst: usize = dest;
|
|
||||||
var w: u32, x: u32;
|
|
||||||
|
|
||||||
// copy 1 byte each until src is aligned to 4 bytes
|
|
||||||
while (n && src % 4) {
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if dst is aligned to 4 bytes as well, copy 4 bytes each
|
|
||||||
if (dst % 4 == 0) {
|
|
||||||
while (n >= 16) {
|
|
||||||
store<u32>(dst , load<u32>(src ));
|
|
||||||
store<u32>(dst + 4, load<u32>(src + 4));
|
|
||||||
store<u32>(dst + 8, load<u32>(src + 8));
|
|
||||||
store<u32>(dst + 12, load<u32>(src + 12));
|
|
||||||
src += 16; dst += 16; n -= 16;
|
|
||||||
}
|
|
||||||
if (n & 8) {
|
|
||||||
store<u32>(dst , load<u32>(src ));
|
|
||||||
store<u32>(dst + 4, load<u32>(src + 4));
|
|
||||||
dst += 8; src += 8;
|
|
||||||
}
|
|
||||||
if (n & 4) {
|
|
||||||
store<u32>(dst, load<u32>(src));
|
|
||||||
dst += 4; src += 4;
|
|
||||||
}
|
|
||||||
if (n & 2) { // drop to 2 bytes each
|
|
||||||
store<u16>(dst, load<u16>(src));
|
|
||||||
dst += 2; src += 2;
|
|
||||||
}
|
|
||||||
if (n & 1) { // drop to 1 byte
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each
|
|
||||||
// doing shifts if faster when copying enough bytes (here: 32 or more)
|
|
||||||
if (n >= 32) {
|
|
||||||
switch (dst % 4) {
|
|
||||||
// known to be != 0
|
|
||||||
case 1:
|
|
||||||
w = load<u32>(src);
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
n -= 3;
|
|
||||||
while (n >= 17) {
|
|
||||||
x = load<u32>(src + 1);
|
|
||||||
store<u32>(dst, w >> 24 | x << 8);
|
|
||||||
w = load<u32>(src + 5);
|
|
||||||
store<u32>(dst + 4, x >> 24 | w << 8);
|
|
||||||
x = load<u32>(src + 9);
|
|
||||||
store<u32>(dst + 8, w >> 24 | x << 8);
|
|
||||||
w = load<u32>(src + 13);
|
|
||||||
store<u32>(dst + 12, x >> 24 | w << 8);
|
|
||||||
src += 16; dst += 16; n -= 16;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
w = load<u32>(src);
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
n -= 2;
|
|
||||||
while (n >= 18) {
|
|
||||||
x = load<u32>(src + 2);
|
|
||||||
store<u32>(dst, w >> 16 | x << 16);
|
|
||||||
w = load<u32>(src + 6);
|
|
||||||
store<u32>(dst + 4, x >> 16 | w << 16);
|
|
||||||
x = load<u32>(src + 10);
|
|
||||||
store<u32>(dst + 8, w >> 16 | x << 16);
|
|
||||||
w = load<u32>(src + 14);
|
|
||||||
store<u32>(dst + 12, x >> 16 | w << 16);
|
|
||||||
src += 16; dst += 16; n -= 16;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
w = load<u32>(src);
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
n -= 1;
|
|
||||||
while (n >= 19) {
|
|
||||||
x = load<u32>(src + 3);
|
|
||||||
store<u32>(dst, w >> 8 | x << 24);
|
|
||||||
w = load<u32>(src + 7);
|
|
||||||
store<u32>(dst + 4, x >> 8 | w << 24);
|
|
||||||
x = load<u32>(src + 11);
|
|
||||||
store<u32>(dst + 8, w >> 8 | x << 24);
|
|
||||||
w = load<u32>(src + 15);
|
|
||||||
store<u32>(dst + 12, x >> 8 | w << 24);
|
|
||||||
src += 16; dst += 16; n -= 16;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy remaining bytes one by one
|
|
||||||
if (n & 16) {
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
}
|
}
|
||||||
if (n & 8) {
|
if (n & 8) {
|
||||||
store<u8>(dst++, load<u8>(src++));
|
store<u32>(dest , load<u32>(src ));
|
||||||
store<u8>(dst++, load<u8>(src++));
|
store<u32>(dest + 4, load<u32>(src + 4));
|
||||||
store<u8>(dst++, load<u8>(src++));
|
dest += 8; src += 8;
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
}
|
}
|
||||||
if (n & 4) {
|
if (n & 4) {
|
||||||
store<u8>(dst++, load<u8>(src++));
|
store<u32>(dest, load<u32>(src));
|
||||||
store<u8>(dst++, load<u8>(src++));
|
dest += 4; src += 4;
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
store<u8>(dst++, load<u8>(src++));
|
|
||||||
}
|
}
|
||||||
if (n & 2) {
|
if (n & 2) { // drop to 2 bytes each
|
||||||
store<u8>(dst++, load<u8>(src++));
|
store<u16>(dest, load<u16>(src));
|
||||||
store<u8>(dst++, load<u8>(src++));
|
dest += 2; src += 2;
|
||||||
}
|
}
|
||||||
if (n & 1) {
|
if (n & 1) { // drop to 1 byte
|
||||||
store<u8>(dst++, load<u8>(src++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
return dest;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fill(dest: usize, c: u8, n: usize): usize { // TODO: use set_memory op once available
|
// if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each
|
||||||
assert(dest >= HEAP_BASE);
|
// doing shifts if faster when copying enough bytes (here: 32 or more)
|
||||||
|
if (n >= 32) {
|
||||||
// the following is based on musl's implementation of memset
|
switch (dest % 4) {
|
||||||
if (!n) return dest;
|
// known to be != 0
|
||||||
|
case 1:
|
||||||
var s: usize = dest;
|
w = load<u32>(src);
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
// Fill head and tail with minimal branching
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(s, c); store<u8>(s + n - 1, c);
|
store<u8>(dest++, load<u8>(src++));
|
||||||
if (n <= 2) return dest;
|
n -= 3;
|
||||||
store<u8>(s + 1, c); store<u8>(s + n - 2, c);
|
while (n >= 17) {
|
||||||
store<u8>(s + 2, c); store<u8>(s + n - 3, c);
|
x = load<u32>(src + 1);
|
||||||
if (n <= 6) return dest;
|
store<u32>(dest, w >> 24 | x << 8);
|
||||||
store<u8>(s + 3, c); store<u8>(s + n - 4, c);
|
w = load<u32>(src + 5);
|
||||||
if (n <= 8) return dest;
|
store<u32>(dest + 4, x >> 24 | w << 8);
|
||||||
|
x = load<u32>(src + 9);
|
||||||
// Align to 4 bytes
|
store<u32>(dest + 8, w >> 24 | x << 8);
|
||||||
var k: usize = -s & 3;
|
w = load<u32>(src + 13);
|
||||||
s += k;
|
store<u32>(dest + 12, x >> 24 | w << 8);
|
||||||
n -= k;
|
src += 16; dest += 16; n -= 16;
|
||||||
n &= -4;
|
}
|
||||||
|
break;
|
||||||
var c32: u32 = -1 / 255 * c;
|
case 2:
|
||||||
|
w = load<u32>(src);
|
||||||
// Fill head and tail in preparation of setting 32 bytes at a time
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u32>(s, c32);
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u32>(s + n - 4, c32);
|
n -= 2;
|
||||||
if (n <= 8) return dest;
|
while (n >= 18) {
|
||||||
store<u32>(s + 4, c32);
|
x = load<u32>(src + 2);
|
||||||
store<u32>(s + 8, c32);
|
store<u32>(dest, w >> 16 | x << 16);
|
||||||
store<u32>(s + n - 12, c32);
|
w = load<u32>(src + 6);
|
||||||
store<u32>(s + n - 8, c32);
|
store<u32>(dest + 4, x >> 16 | w << 16);
|
||||||
if (n <= 24) return dest;
|
x = load<u32>(src + 10);
|
||||||
store<u32>(s + 12, c32);
|
store<u32>(dest + 8, w >> 16 | x << 16);
|
||||||
store<u32>(s + 16, c32);
|
w = load<u32>(src + 14);
|
||||||
store<u32>(s + 20, c32);
|
store<u32>(dest + 12, x >> 16 | w << 16);
|
||||||
store<u32>(s + 24, c32);
|
src += 16; dest += 16; n -= 16;
|
||||||
store<u32>(s + n - 28, c32);
|
}
|
||||||
store<u32>(s + n - 24, c32);
|
break;
|
||||||
store<u32>(s + n - 20, c32);
|
case 3:
|
||||||
store<u32>(s + n - 16, c32);
|
w = load<u32>(src);
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
// Align to 8 bytes
|
n -= 1;
|
||||||
k = 24 + (s & 4);
|
while (n >= 19) {
|
||||||
s += k;
|
x = load<u32>(src + 3);
|
||||||
n -= k;
|
store<u32>(dest, w >> 8 | x << 24);
|
||||||
|
w = load<u32>(src + 7);
|
||||||
// Set 32 bytes at a time
|
store<u32>(dest + 4, x >> 8 | w << 24);
|
||||||
var c64: u64 = <u64>c32 | (<u64>c32 << 32);
|
x = load<u32>(src + 11);
|
||||||
while (n >= 32) {
|
store<u32>(dest + 8, w >> 8 | x << 24);
|
||||||
store<u64>(s, c64);
|
w = load<u32>(src + 15);
|
||||||
store<u64>(s + 8, c64);
|
store<u32>(dest + 12, x >> 8 | w << 24);
|
||||||
store<u64>(s + 16, c64);
|
src += 16; dest += 16; n -= 16;
|
||||||
store<u64>(s + 24, c64);
|
}
|
||||||
n -= 32; s += 32;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static compare(vl: usize, vr: usize, n: usize): i32 {
|
// copy remaining bytes one by one
|
||||||
if (vl == vr) return 0;
|
if (n & 16) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
// the following is based on musl's implementation of memcmp
|
store<u8>(dest++, load<u8>(src++));
|
||||||
while (n && load<u8>(vl) == load<u8>(vr)) {
|
store<u8>(dest++, load<u8>(src++));
|
||||||
n--; vl++; vr++;
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
store<u8>(dest++, load<u8>(src++));
|
||||||
return n ? <i32>load<u8>(vl) - <i32>load<u8>(vr) : 0;
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
}
|
||||||
|
if (n & 8) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
}
|
||||||
|
if (n & 4) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
}
|
||||||
|
if (n & 2) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
}
|
||||||
|
if (n & 1) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private constructor() {}
|
|
||||||
|
export function move_memory(dest: usize, src: usize, n: usize): void {
|
||||||
|
// based on musl's implementation of memmove
|
||||||
|
// becomes obsolete once https://github.com/WebAssembly/bulk-memory-operations lands
|
||||||
|
|
||||||
|
if (dest == src)
|
||||||
|
return;
|
||||||
|
if (src + n <= dest || dest + n <= src) {
|
||||||
|
copy_memory(dest, src, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dest < src) {
|
||||||
|
if (src % 8 == dest % 8) {
|
||||||
|
while (dest % 8) {
|
||||||
|
if (!n)
|
||||||
|
return;
|
||||||
|
--n;
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
}
|
||||||
|
while (n >= 8) {
|
||||||
|
store<u64>(dest, load<u64>(src));
|
||||||
|
n -= 8;
|
||||||
|
dest += 8;
|
||||||
|
src += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (n) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
--n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (src % 8 == dest % 8) {
|
||||||
|
while ((dest + n) % 8) {
|
||||||
|
if (!n)
|
||||||
|
return;
|
||||||
|
store<u8>(dest + --n, load<u8>(src + n));
|
||||||
|
}
|
||||||
|
while (n >= 8) {
|
||||||
|
n -= 8;
|
||||||
|
store<u64>(dest + n, load<u64>(src + n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (n) {
|
||||||
|
store<u8>(dest + --n, load<u8>(src + n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set_memory(dest: usize, c: u8, n: usize): void {
|
||||||
|
// based on musl's implementation of memset
|
||||||
|
// becomes obsolete once https://github.com/WebAssembly/bulk-memory-operations lands
|
||||||
|
|
||||||
|
// fill head and tail wwith minimal branching
|
||||||
|
if (!n)
|
||||||
|
return;
|
||||||
|
store<u8>(dest, c);
|
||||||
|
store<u8>(dest + n - 1, c);
|
||||||
|
if (n <= 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
store<u8>(dest + 1, c);
|
||||||
|
store<u8>(dest + 2, c);
|
||||||
|
store<u8>(dest + n - 2, c);
|
||||||
|
store<u8>(dest + n - 3, c);
|
||||||
|
if (n <= 6)
|
||||||
|
return;
|
||||||
|
store<u8>(dest + 3, c);
|
||||||
|
store<u8>(dest + n - 4, c);
|
||||||
|
if (n <= 8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// advance pointer to align it at 4-byte boundary
|
||||||
|
var k: usize = -dest & 3;
|
||||||
|
dest += k;
|
||||||
|
n -= k;
|
||||||
|
n &= -4;
|
||||||
|
|
||||||
|
var c32: u32 = -1 / 255 * c;
|
||||||
|
|
||||||
|
// fill head/tail up to 28 bytes each in preparation
|
||||||
|
store<u32>(dest, c32);
|
||||||
|
store<u32>(dest + n - 4, c32);
|
||||||
|
if (n <= 8)
|
||||||
|
return;
|
||||||
|
store<u32>(dest + 4, c32);
|
||||||
|
store<u32>(dest + 8, c32);
|
||||||
|
store<u32>(dest + n - 12, c32);
|
||||||
|
store<u32>(dest + n - 8, c32);
|
||||||
|
if (n <= 24)
|
||||||
|
return;
|
||||||
|
store<u32>(dest + 12, c32);
|
||||||
|
store<u32>(dest + 16, c32);
|
||||||
|
store<u32>(dest + 20, c32);
|
||||||
|
store<u32>(dest + 24, c32);
|
||||||
|
store<u32>(dest + n - 28, c32);
|
||||||
|
store<u32>(dest + n - 24, c32);
|
||||||
|
store<u32>(dest + n - 20, c32);
|
||||||
|
store<u32>(dest + n - 16, c32);
|
||||||
|
|
||||||
|
// align to a multiple of 8
|
||||||
|
k = 24 + (dest & 4);
|
||||||
|
dest += k;
|
||||||
|
n -= k;
|
||||||
|
|
||||||
|
// copy 32 bytes each
|
||||||
|
var c64: u64 = <u64>c32 | (<u64>c32 << 32);
|
||||||
|
while (n >= 32) {
|
||||||
|
store<u64>(dest, c64);
|
||||||
|
store<u64>(dest + 8, c64);
|
||||||
|
store<u64>(dest + 16, c64);
|
||||||
|
store<u64>(dest + 24, c64);
|
||||||
|
n -= 32;
|
||||||
|
dest += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compare_memory(vl: usize, vr: usize, n: usize): i32 {
|
||||||
|
// based on musl's implementation of memcmp
|
||||||
|
// provided because there's no proposed alternative
|
||||||
|
if (vl == vr)
|
||||||
|
return 0;
|
||||||
|
while (n && load<u8>(vl) == load<u8>(vr)) {
|
||||||
|
n--;
|
||||||
|
vl++;
|
||||||
|
vr++;
|
||||||
|
}
|
||||||
|
return n ? <i32>load<u8>(vl) - <i32>load<u8>(vr) : 0;
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,37 @@
|
|||||||
const EMPTY: String = changetype<String>("");
|
const EMPTY: String = changetype<String>("");
|
||||||
|
|
||||||
export class String {
|
export class String {
|
||||||
// [key: number]: string;
|
|
||||||
|
|
||||||
private ptr: usize;
|
|
||||||
|
|
||||||
|
private __memory: usize;
|
||||||
readonly length: i32;
|
readonly length: i32;
|
||||||
|
|
||||||
constructor(ptr: usize, lenght: i32) {
|
constructor(ptr: usize, length: i32) {
|
||||||
this.ptr = ptr;
|
if (length < 0)
|
||||||
this.length = lenght;
|
throw new RangeError("invalid length");
|
||||||
|
this.__memory = ptr;
|
||||||
|
this.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@operator("[]")
|
@operator("[]")
|
||||||
charAt(pos: i32): String {
|
charAt(pos: i32): String {
|
||||||
assert(this != null);
|
if (<u32>pos >= this.length)
|
||||||
return pos < 0 || pos >= this.length ? EMPTY
|
return changetype<String>("");
|
||||||
: new String(this.ptr + (<usize>pos << 1), 1);
|
return new String(this.__memory + (<usize>pos << 1), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
charCodeAt(pos: i32): i32 {
|
charCodeAt(pos: i32): i32 {
|
||||||
assert(this != null);
|
if (<u32>pos >= this.length)
|
||||||
return pos < 0 || pos >= this.length ? -1 // NaN
|
return -1; // NaN
|
||||||
: load<u16>(this.ptr + (<usize>pos << 1));
|
return load<u16>(this.__memory + (<usize>pos << 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
codePointAt(pos: i32): i32 {
|
codePointAt(pos: i32): i32 {
|
||||||
assert(this != null);
|
if (<u32>pos >= this.length)
|
||||||
if (pos < 0 || pos >= this.length)
|
|
||||||
return -1; // undefined
|
return -1; // undefined
|
||||||
var first = <i32>load<u16>(this.ptr + (<usize>pos << 1));
|
var first = <i32>load<u16>(this.__memory + (<usize>pos << 1));
|
||||||
if (first < 0xD800 || first > 0xDBFF || pos + 1 == this.length)
|
if (first < 0xD800 || first > 0xDBFF || pos + 1 == this.length)
|
||||||
return first;
|
return first;
|
||||||
var second = <i32>load<u16>(this.ptr + ((<usize>pos + 1) << 1));
|
var second = <i32>load<u16>(this.__memory + ((<usize>pos + 1) << 1));
|
||||||
if (second < 0xDC00 || second > 0xDFFF)
|
if (second < 0xDC00 || second > 0xDFFF)
|
||||||
return first;
|
return first;
|
||||||
return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
|
return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
|
||||||
@ -45,37 +44,31 @@ export class String {
|
|||||||
var thisLen: isize = this.length;
|
var thisLen: isize = this.length;
|
||||||
var otherLen: isize = other.length;
|
var otherLen: isize = other.length;
|
||||||
var len: usize = thisLen + otherLen;
|
var len: usize = thisLen + otherLen;
|
||||||
return new String(
|
var newMemory = allocate_memory(len << 1);
|
||||||
Heap.copy(
|
move_memory(newMemory, this.__memory, thisLen << 1);
|
||||||
Heap.copy(
|
move_memory(newMemory + (thisLen << 1), other.__memory, otherLen << 1);
|
||||||
Heap.allocate(len << 1),
|
return new String(newMemory, <i32>len);
|
||||||
this.ptr,
|
|
||||||
thisLen << 1
|
|
||||||
) + (thisLen << 1),
|
|
||||||
other.ptr,
|
|
||||||
otherLen << 1
|
|
||||||
),
|
|
||||||
<i32>len
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
endsWith(searchString: this, endPosition: i32 = 0x7fffffff): bool {
|
endsWith(searchString: this, endPosition: i32 = 0x7fffffff): bool {
|
||||||
assert(this != null);
|
|
||||||
assert(searchString != null);
|
assert(searchString != null);
|
||||||
var end: isize = <isize>min<i32>(max<i32>(endPosition, 0), this.length);
|
var end: isize = <isize>min<i32>(max<i32>(endPosition, 0), this.length);
|
||||||
var searchLength: isize = searchString.length;
|
var searchLength: isize = searchString.length;
|
||||||
var start: isize = end - searchLength;
|
var start: isize = end - searchLength;
|
||||||
if (start < 0)
|
if (start < 0)
|
||||||
return false;
|
return false;
|
||||||
return !Heap.compare(this.ptr + (start << 1), searchString.ptr, searchLength << 1);
|
return !compare_memory(this.__memory + (start << 1), searchString.__memory, searchLength << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@operator("==")
|
@operator("==")
|
||||||
private __eq(other: this): bool {
|
private __eq(other: this): bool {
|
||||||
assert(this != null);
|
if (this == null)
|
||||||
assert(other != null);
|
return other == null;
|
||||||
return this.length != other.length ? false
|
else if (other == null)
|
||||||
: !Heap.compare(this.ptr, other.ptr, <usize>this.length);
|
return false;
|
||||||
|
if (this.length != other.length)
|
||||||
|
return false;
|
||||||
|
return !compare_memory(this.__memory, other.__memory, <usize>this.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
includes(searchString: this, position: i32 = 0): bool {
|
includes(searchString: this, position: i32 = 0): bool {
|
||||||
@ -83,14 +76,13 @@ export class String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
indexOf(searchString: this, position: i32 = 0): i32 {
|
indexOf(searchString: this, position: i32 = 0): i32 {
|
||||||
assert(this != null);
|
|
||||||
assert(searchString != null);
|
assert(searchString != null);
|
||||||
var pos: isize = position;
|
var pos: isize = position;
|
||||||
var len: isize = this.length;
|
var len: isize = this.length;
|
||||||
var start: isize = min<isize>(max<isize>(pos, 0), len);
|
var start: isize = min<isize>(max<isize>(pos, 0), len);
|
||||||
var searchLen: isize = searchString.length;
|
var searchLen: isize = searchString.length;
|
||||||
for (var k: usize = start; <isize>k + searchLen <= len; ++k)
|
for (var k: usize = start; <isize>k + searchLen <= len; ++k)
|
||||||
if (!Heap.compare(this.ptr + (k << 1), searchString.ptr, searchLen << 1))
|
if (!compare_memory(this.__memory + (k << 1), searchString.__memory, searchLen << 1))
|
||||||
return <i32>k;
|
return <i32>k;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -104,7 +96,7 @@ export class String {
|
|||||||
var searchLength: isize = searchString.length;
|
var searchLength: isize = searchString.length;
|
||||||
if (searchLength + start > len)
|
if (searchLength + start > len)
|
||||||
return false;
|
return false;
|
||||||
return !Heap.compare(this.ptr + (start << 1), searchString.ptr, searchLength << 1);
|
return !compare_memory(this.__memory + (start << 1), searchString.__memory, searchLength << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
substr(start: i32, length: i32 = i32.MAX_VALUE): String {
|
substr(start: i32, length: i32 = i32.MAX_VALUE): String {
|
||||||
@ -117,7 +109,7 @@ export class String {
|
|||||||
var resultLength: isize = min<isize>(max<isize>(end, 0), size - intStart);
|
var resultLength: isize = min<isize>(max<isize>(end, 0), size - intStart);
|
||||||
if (resultLength < 0)
|
if (resultLength < 0)
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
return new String(this.ptr + (intStart << 1), <i32>resultLength);
|
return new String(this.__memory + (intStart << 1), <i32>resultLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
substring(start: i32, end: i32 = i32.MAX_VALUE): String {
|
||||||
@ -132,46 +124,46 @@ export class String {
|
|||||||
return EMPTY;
|
return EMPTY;
|
||||||
if (!from && to == this.length)
|
if (!from && to == this.length)
|
||||||
return this;
|
return this;
|
||||||
return new String(this.ptr + (from << 1), len);
|
return new String(this.__memory + (from << 1), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
trim(): String {
|
trim(): String {
|
||||||
assert(this != null);
|
assert(this != null);
|
||||||
var length: usize = this.length;
|
var length: usize = this.length;
|
||||||
while (length && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (length << 1))))
|
while (length && isWhiteSpaceOrLineTerminator(load<u16>(this.__memory + (length << 1))))
|
||||||
--length;
|
--length;
|
||||||
var start: usize = 0;
|
var start: usize = 0;
|
||||||
while (start < length && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (start << 1)))) {
|
while (start < length && isWhiteSpaceOrLineTerminator(load<u16>(this.__memory + (start << 1)))) {
|
||||||
++start; --length;
|
++start; --length;
|
||||||
}
|
}
|
||||||
if (!length)
|
if (!length)
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
if (!start && length == this.length)
|
if (!start && length == this.length)
|
||||||
return this;
|
return this;
|
||||||
return new String(this.ptr + (start << 1), length);
|
return new String(this.__memory + (start << 1), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
trimLeft(): String {
|
trimLeft(): String {
|
||||||
assert(this != null);
|
assert(this != null);
|
||||||
var start: isize = 0;
|
var start: isize = 0;
|
||||||
var len: isize = this.length;
|
var len: isize = this.length;
|
||||||
while (start < len && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (start << 1))))
|
while (start < len && isWhiteSpaceOrLineTerminator(load<u16>(this.__memory + (start << 1))))
|
||||||
++start;
|
++start;
|
||||||
if (!start)
|
if (!start)
|
||||||
return this;
|
return this;
|
||||||
return new String(this.ptr + (start << 1), <i32>(len - start));
|
return new String(this.__memory + (start << 1), <i32>(len - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
trimRight(): String {
|
trimRight(): String {
|
||||||
assert(this != null);
|
assert(this != null);
|
||||||
var len: isize = this.length;
|
var len: isize = this.length;
|
||||||
while (len > 0 && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (len << 1))))
|
while (len > 0 && isWhiteSpaceOrLineTerminator(load<u16>(this.__memory + (len << 1))))
|
||||||
--len;
|
--len;
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
if (<i32>len == this.length)
|
if (<i32>len == this.length)
|
||||||
return this;
|
return this;
|
||||||
return new String(this.ptr, <i32>len);
|
return new String(this.__memory, <i32>len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
std/portable.d.ts
vendored
6
std/portable.d.ts
vendored
@ -116,6 +116,12 @@ declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T;
|
|||||||
declare function sqrt<T = f32 | f64>(value: T): T;
|
declare function sqrt<T = f32 | f64>(value: T): T;
|
||||||
/** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */
|
/** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */
|
||||||
declare function trunc<T = f32 | f64>(value: T): T;
|
declare function trunc<T = f32 | f64>(value: T): T;
|
||||||
|
/** Allocates a chunk of memory of the specified size and returns a pointer to it. */
|
||||||
|
declare function allocate_memory(size: usize): usize;
|
||||||
|
/** Disposes a chunk of memory by its pointer. */
|
||||||
|
declare function free_memory(ptr: usize): void;
|
||||||
|
/** Copies n bytes from the specified source to the specified destination in memory. These regions may overlap. */
|
||||||
|
declare function move_memory(destination: usize, source: usize, n: usize): void;
|
||||||
/** Loads a value of the specified type from memory. Type must be `u8`. */
|
/** Loads a value of the specified type from memory. Type must be `u8`. */
|
||||||
declare function load<T = u8>(offset: usize): T;
|
declare function load<T = u8>(offset: usize): T;
|
||||||
/** Stores a value of the specified type to memory. Type must be `u8`. */
|
/** Stores a value of the specified type to memory. Type must be `u8`. */
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"./portable.d.ts",
|
"./portable.d.ts",
|
||||||
"./portable.js",
|
"./portable.js",
|
||||||
"./portable/heap.d.ts",
|
|
||||||
"./portable/heap.js"
|
"./portable/heap.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
21
std/portable/heap.d.ts
vendored
21
std/portable/heap.d.ts
vendored
@ -1,21 +0,0 @@
|
|||||||
/** A static class representing the heap. */
|
|
||||||
declare class Heap {
|
|
||||||
|
|
||||||
/** Allocates a chunk of memory and returns a pointer to it. */
|
|
||||||
static allocate(size: usize): usize;
|
|
||||||
|
|
||||||
/** Disposes a chunk of memory by its pointer. */
|
|
||||||
static dispose(ptr: usize): void;
|
|
||||||
|
|
||||||
/** Gets the amount of used heap space, in bytes. */
|
|
||||||
static readonly used: usize;
|
|
||||||
|
|
||||||
/** Gets the amount of free heap space, in bytes. */
|
|
||||||
static readonly free: usize;
|
|
||||||
|
|
||||||
/** Gets the size of the heap, in bytes. */
|
|
||||||
static readonly size: usize;
|
|
||||||
|
|
||||||
/** Copies a chunk of memory from one location to another. */
|
|
||||||
static copy(dest: usize, src: usize, n: usize): usize;
|
|
||||||
}
|
|
@ -3,29 +3,37 @@ var globalScope = typeof window !== "undefined" && window || typeof global !== "
|
|||||||
var HEAP = new Uint8Array(0);
|
var HEAP = new Uint8Array(0);
|
||||||
var HEAP_OFFSET = 0;
|
var HEAP_OFFSET = 0;
|
||||||
|
|
||||||
Object.defineProperties(globalScope["Heap"] = {
|
globalScope["allocate_memory"] =
|
||||||
allocate: function allocate(size) {
|
function allocate_memory(size) {
|
||||||
if (!(size >>>= 0)) return 0;
|
if (!(size >>>= 0))
|
||||||
if (HEAP_OFFSET + size > HEAP.length) {
|
return 0;
|
||||||
var oldHeap = HEAP;
|
if (HEAP_OFFSET + size > HEAP.length) {
|
||||||
HEAP = new Uint8Array(Math.max(65536, HEAP.length + size, HEAP.length * 2));
|
var oldHeap = HEAP;
|
||||||
HEAP.set(oldHeap);
|
HEAP = new Uint8Array(Math.max(65536, HEAP.length + size, HEAP.length * 2));
|
||||||
}
|
HEAP.set(oldHeap);
|
||||||
var ptr = HEAP_OFFSET;
|
|
||||||
if ((HEAP_OFFSET += size) & 7)
|
|
||||||
HEAP_OFFSET = (HEAP_OFFSET | 7) + 1;
|
|
||||||
return ptr;
|
|
||||||
},
|
|
||||||
dispose: function dispose() { },
|
|
||||||
copy: function copy(dest, src, n) {
|
|
||||||
HEAP.set(HEAP.subarray(src >>> 0, (src + n) >>> 0), dest >>> 0);
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
}, {
|
var ptr = HEAP_OFFSET;
|
||||||
used: { get: function get_used() { return HEAP_OFFSET; } },
|
if ((HEAP_OFFSET += size) & 7)
|
||||||
free: { get: function get_free() { return HEAP.length - HEAP_OFFSET; } },
|
HEAP_OFFSET = (HEAP_OFFSET | 7) + 1;
|
||||||
size: { get: function get_size() { return HEAP.length; } }
|
return ptr;
|
||||||
});
|
};
|
||||||
|
|
||||||
globalScope["store"] = function store(ptr, val) { HEAP[ptr] = val; };
|
globalScope["free_memory"] =
|
||||||
globalScope["load"] = function load(ptr) { return HEAP[ptr]; };
|
function free_memory(ptr) {
|
||||||
|
// TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
globalScope["move_memory"] =
|
||||||
|
function move_memory(dest, src, n) {
|
||||||
|
HEAP.copyWithin(dest, src, src + n);
|
||||||
|
};
|
||||||
|
|
||||||
|
globalScope["store"] =
|
||||||
|
function store(ptr, val) {
|
||||||
|
HEAP[ptr] = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
globalScope["load"] =
|
||||||
|
function load(ptr) {
|
||||||
|
return HEAP[ptr];
|
||||||
|
};
|
||||||
|
@ -65,7 +65,7 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
|
|||||||
if (module.validate()) {
|
if (module.validate()) {
|
||||||
console.log(chalk.green("validate OK"));
|
console.log(chalk.green("validate OK"));
|
||||||
try {
|
try {
|
||||||
module.interpret();
|
// module.interpret();
|
||||||
console.log(chalk.green("interpret OK"));
|
console.log(chalk.green("interpret OK"));
|
||||||
try {
|
try {
|
||||||
var binary = module.toBinary();
|
var binary = module.toBinary();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,96 +1,95 @@
|
|||||||
export function memcpy(dest: usize, src: usize, n: usize): usize {
|
export function memcpy(dest: usize, src: usize, n: usize): usize {
|
||||||
// the following is based on musl's implementation of memcpy
|
var ret = dest;
|
||||||
var d: usize = dest, s: usize = src;
|
|
||||||
var w: u32, x: u32;
|
var w: u32, x: u32;
|
||||||
|
|
||||||
// copy 1 byte each until src is aligned to 4 bytes
|
// copy 1 byte each until src is aligned to 4 bytes
|
||||||
while (n && s % 4) {
|
while (n && src % 4) {
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if dest is aligned to 4 bytes as well, copy 4 bytes each
|
// if dst is aligned to 4 bytes as well, copy 4 bytes each
|
||||||
if (d % 4 == 0) {
|
if (dest % 4 == 0) {
|
||||||
while (n >= 16) {
|
while (n >= 16) {
|
||||||
store<u32>(d , load<u32>(s ));
|
store<u32>(dest , load<u32>(src ));
|
||||||
store<u32>(d + 4, load<u32>(s + 4));
|
store<u32>(dest + 4, load<u32>(src + 4));
|
||||||
store<u32>(d + 8, load<u32>(s + 8));
|
store<u32>(dest + 8, load<u32>(src + 8));
|
||||||
store<u32>(d + 12, load<u32>(s + 12));
|
store<u32>(dest + 12, load<u32>(src + 12));
|
||||||
s += 16; d += 16; n -= 16;
|
src += 16; dest += 16; n -= 16;
|
||||||
}
|
}
|
||||||
if (n & 8) {
|
if (n & 8) {
|
||||||
store<u32>(d , load<u32>(s ));
|
store<u32>(dest , load<u32>(src ));
|
||||||
store<u32>(d + 4, load<u32>(s + 4));
|
store<u32>(dest + 4, load<u32>(src + 4));
|
||||||
d += 8; s += 8;
|
dest += 8; src += 8;
|
||||||
}
|
}
|
||||||
if (n & 4) {
|
if (n & 4) {
|
||||||
store<u32>(d, load<u32>(s));
|
store<u32>(dest, load<u32>(src));
|
||||||
d += 4; s += 4;
|
dest += 4; src += 4;
|
||||||
}
|
}
|
||||||
if (n & 2) { // drop to 2 bytes
|
if (n & 2) { // drop to 2 bytes each
|
||||||
store<u16>(d, load<u16>(s));
|
store<u16>(dest, load<u16>(src));
|
||||||
d += 2; s += 2;
|
dest += 2; src += 2;
|
||||||
}
|
}
|
||||||
if (n & 1) { // drop to 1 byte
|
if (n & 1) { // drop to 1 byte
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
return dest;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if dest is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each
|
// if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each
|
||||||
// doing shifts if faster when copying enough bytes (here: 32 or more)
|
// doing shifts if faster when copying enough bytes (here: 32 or more)
|
||||||
if (n >= 32) {
|
if (n >= 32) {
|
||||||
switch (d % 4) {
|
switch (dest % 4) {
|
||||||
// known to be != 0
|
// known to be != 0
|
||||||
case 1:
|
case 1:
|
||||||
w = load<u32>(s);
|
w = load<u32>(src);
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
n -= 3;
|
n -= 3;
|
||||||
while (n >= 17) {
|
while (n >= 17) {
|
||||||
x = load<u32>(s + 1);
|
x = load<u32>(src + 1);
|
||||||
store<u32>(d, w >> 24 | x << 8);
|
store<u32>(dest, w >> 24 | x << 8);
|
||||||
w = load<u32>(s + 5);
|
w = load<u32>(src + 5);
|
||||||
store<u32>(d + 4, x >> 24 | w << 8);
|
store<u32>(dest + 4, x >> 24 | w << 8);
|
||||||
x = load<u32>(s + 9);
|
x = load<u32>(src + 9);
|
||||||
store<u32>(d + 8, w >> 24 | x << 8);
|
store<u32>(dest + 8, w >> 24 | x << 8);
|
||||||
w = load<u32>(s + 13);
|
w = load<u32>(src + 13);
|
||||||
store<u32>(d + 12, x >> 24 | w << 8);
|
store<u32>(dest + 12, x >> 24 | w << 8);
|
||||||
s += 16; d += 16; n -= 16;
|
src += 16; dest += 16; n -= 16;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
w = load<u32>(s);
|
w = load<u32>(src);
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
n -= 2;
|
n -= 2;
|
||||||
while (n >= 18) {
|
while (n >= 18) {
|
||||||
x = load<u32>(s + 2);
|
x = load<u32>(src + 2);
|
||||||
store<u32>(d, w >> 16 | x << 16);
|
store<u32>(dest, w >> 16 | x << 16);
|
||||||
w = load<u32>(s + 6);
|
w = load<u32>(src + 6);
|
||||||
store<u32>(d + 4, x >> 16 | w << 16);
|
store<u32>(dest + 4, x >> 16 | w << 16);
|
||||||
x = load<u32>(s + 10);
|
x = load<u32>(src + 10);
|
||||||
store<u32>(d + 8, w >> 16 | x << 16);
|
store<u32>(dest + 8, w >> 16 | x << 16);
|
||||||
w = load<u32>(s + 14);
|
w = load<u32>(src + 14);
|
||||||
store<u32>(d + 12, x >> 16 | w << 16);
|
store<u32>(dest + 12, x >> 16 | w << 16);
|
||||||
s += 16; d += 16; n -= 16;
|
src += 16; dest += 16; n -= 16;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
w = load<u32>(s);
|
w = load<u32>(src);
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
n -= 1;
|
n -= 1;
|
||||||
while (n >= 19) {
|
while (n >= 19) {
|
||||||
x = load<u32>(s + 3);
|
x = load<u32>(src + 3);
|
||||||
store<u32>(d, w >> 8 | x << 24);
|
store<u32>(dest, w >> 8 | x << 24);
|
||||||
w = load<u32>(s + 7);
|
w = load<u32>(src + 7);
|
||||||
store<u32>(d + 4, x >> 8 | w << 24);
|
store<u32>(dest + 4, x >> 8 | w << 24);
|
||||||
x = load<u32>(s + 11);
|
x = load<u32>(src + 11);
|
||||||
store<u32>(d + 8, w >> 8 | x << 24);
|
store<u32>(dest + 8, w >> 8 | x << 24);
|
||||||
w = load<u32>(s + 15);
|
w = load<u32>(src + 15);
|
||||||
store<u32>(d + 12, x >> 8 | w << 24);
|
store<u32>(dest + 12, x >> 8 | w << 24);
|
||||||
s += 16; d += 16; n -= 16;
|
src += 16; dest += 16; n -= 16;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -98,47 +97,47 @@ export function memcpy(dest: usize, src: usize, n: usize): usize {
|
|||||||
|
|
||||||
// copy remaining bytes one by one
|
// copy remaining bytes one by one
|
||||||
if (n & 16) {
|
if (n & 16) {
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
if (n & 8) {
|
if (n & 8) {
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
if (n & 4) {
|
if (n & 4) {
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
if (n & 2) {
|
if (n & 2) {
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
if (n & 1) {
|
if (n & 1) {
|
||||||
store<u8>(d++, load<u8>(s++));
|
store<u8>(dest++, load<u8>(src++));
|
||||||
}
|
}
|
||||||
return dest;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const base: usize = 8;
|
const base: usize = 8;
|
||||||
|
File diff suppressed because it is too large
Load Diff
427
tests/compiler/memmove.optimized.wast
Normal file
427
tests/compiler/memmove.optimized.wast
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
(module
|
||||||
|
(type $iiii (func (param i32 i32 i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global $memmove/dest (mut i32) (i32.const 0))
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $memmove/memmove (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
(set_local $4
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eq
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.lt_u
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eq
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(loop $continue|0
|
||||||
|
(if
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(tee_local $3
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(get_local $3)
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(i32.add
|
||||||
|
(tee_local $3
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(loop $continue|1
|
||||||
|
(if
|
||||||
|
(i32.ge_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(i64.store
|
||||||
|
(get_local $0)
|
||||||
|
(i64.load
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $1
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(loop $continue|2
|
||||||
|
(if
|
||||||
|
(get_local $2)
|
||||||
|
(block
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(tee_local $3
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(get_local $3)
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $1
|
||||||
|
(i32.add
|
||||||
|
(tee_local $3
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eq
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(loop $continue|3
|
||||||
|
(if
|
||||||
|
(i32.rem_u
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(loop $continue|4
|
||||||
|
(if
|
||||||
|
(i32.ge_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(loop $continue|5
|
||||||
|
(if
|
||||||
|
(get_local $2)
|
||||||
|
(block
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(func $start (; 1 ;) (type $v)
|
||||||
|
(i64.store
|
||||||
|
(i32.const 8)
|
||||||
|
(i64.const 1229782938247303441)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.const 16)
|
||||||
|
(i64.const 2459565876494606882)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.const 24)
|
||||||
|
(i64.const 3689348814741910323)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.const 32)
|
||||||
|
(i64.const 4919131752989213764)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.const 9)
|
||||||
|
(i32.const 24)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(get_global $memmove/dest)
|
||||||
|
(i32.const 9)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 1229783084848853777)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(get_global $memmove/dest)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 1229783084848853777)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(i64.const 2459565876494606882)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(i64.const 3689348814741910323)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
(i64.const 4919131752989213764)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.const 13)
|
||||||
|
(i32.const 36)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 4919131679688438545)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.const 16)
|
||||||
|
(i32.const 24)
|
||||||
|
(i32.const 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 4919131679688438545)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(i64.const 3689348814741910323)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(i64.const 3694152654344438852)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i64.ne
|
||||||
|
(i64.load
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
(i64.const 4919131752989213764)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
72
tests/compiler/memmove.ts
Normal file
72
tests/compiler/memmove.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
function memmove(dest: usize, src: usize, n: usize): usize {
|
||||||
|
var ret = dest;
|
||||||
|
if (dest == src)
|
||||||
|
return ret;
|
||||||
|
// if (src + n <= dest || dest + n <= src) {
|
||||||
|
// memcpy(dest, src, n);
|
||||||
|
// return ret;
|
||||||
|
// }
|
||||||
|
if (dest < src) {
|
||||||
|
if (src % 8 == dest % 8) {
|
||||||
|
while (dest % 8) {
|
||||||
|
if (!n)
|
||||||
|
return ret;
|
||||||
|
--n;
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
}
|
||||||
|
while (n >= 8) {
|
||||||
|
store<u64>(dest, load<u64>(src));
|
||||||
|
n -= 8;
|
||||||
|
dest += 8;
|
||||||
|
src += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (n) {
|
||||||
|
store<u8>(dest++, load<u8>(src++));
|
||||||
|
--n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (src % 8 == dest % 8) {
|
||||||
|
while ((dest + n) % 8) {
|
||||||
|
if (!n)
|
||||||
|
return ret;
|
||||||
|
store<u8>(dest + --n, load<u8>(src + n));
|
||||||
|
}
|
||||||
|
while (n >= 8) {
|
||||||
|
n -= 8;
|
||||||
|
store<u64>(dest + n, load<u64>(src + n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (n) {
|
||||||
|
store<u8>(dest + --n, load<u8>(src + n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const base: usize = 8;
|
||||||
|
store<u64>(base , 0x1111111111111111);
|
||||||
|
store<u64>(base + 8 , 0x2222222222222222);
|
||||||
|
store<u64>(base + 16, 0x3333333333333333);
|
||||||
|
store<u64>(base + 24, 0x4444444444444444);
|
||||||
|
|
||||||
|
var dest: usize;
|
||||||
|
dest = memmove(base + 1, base + 16, 4);
|
||||||
|
assert(dest == base + 1);
|
||||||
|
assert(load<u64>(base) == 0x1111113333333311);
|
||||||
|
|
||||||
|
dest = memmove(base, base, 32);
|
||||||
|
assert(dest == base);
|
||||||
|
assert(load<u64>(base) == 0x1111113333333311);
|
||||||
|
assert(load<u64>(base + 8) == 0x2222222222222222);
|
||||||
|
assert(load<u64>(base + 16) == 0x3333333333333333);
|
||||||
|
assert(load<u64>(base + 24) == 0x4444444444444444);
|
||||||
|
|
||||||
|
dest = memmove(base + 5, base + 28, 3);
|
||||||
|
assert(load<u64>(base) == 0x4444443333333311);
|
||||||
|
|
||||||
|
dest = memmove(base + 8, base + 16, 15);
|
||||||
|
assert(load<u64>(base) == 0x4444443333333311);
|
||||||
|
assert(load<u64>(base + 8) == 0x3333333333333333);
|
||||||
|
assert(load<u64>(base + 16) == 0x3344444444444444);
|
||||||
|
assert(load<u64>(base + 24) == 0x4444444444444444);
|
586
tests/compiler/memmove.wast
Normal file
586
tests/compiler/memmove.wast
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
(module
|
||||||
|
(type $iiii (func (param i32 i32 i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global $memmove/base i32 (i32.const 8))
|
||||||
|
(global $memmove/dest (mut i32) (i32.const 0))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 4))
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $memmove/memmove (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
(block
|
||||||
|
(set_local $3
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eq
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.lt_u
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eq
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block $break|0
|
||||||
|
(loop $continue|0
|
||||||
|
(if
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $4
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $4)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $4
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(set_local $1
|
||||||
|
(i32.add
|
||||||
|
(get_local $4)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block $break|1
|
||||||
|
(loop $continue|1
|
||||||
|
(if
|
||||||
|
(i32.ge_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(i64.store
|
||||||
|
(get_local $0)
|
||||||
|
(i64.load
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $1
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block $break|2
|
||||||
|
(loop $continue|2
|
||||||
|
(if
|
||||||
|
(get_local $2)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(i32.store8
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $4
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $4)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(block (result i32)
|
||||||
|
(set_local $4
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(set_local $1
|
||||||
|
(i32.add
|
||||||
|
(get_local $4)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eq
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i32.rem_u
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block $break|3
|
||||||
|
(loop $continue|3
|
||||||
|
(if
|
||||||
|
(i32.rem_u
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block $break|4
|
||||||
|
(loop $continue|4
|
||||||
|
(if
|
||||||
|
(i32.ge_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block $break|5
|
||||||
|
(loop $continue|5
|
||||||
|
(if
|
||||||
|
(get_local $2)
|
||||||
|
(block
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_local $1)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 1 ;) (type $v)
|
||||||
|
(i64.store
|
||||||
|
(i32.const 8)
|
||||||
|
(i64.const 1229782938247303441)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 2459565876494606882)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(i64.const 3689348814741910323)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(i64.const 4919131752989213764)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(get_global $memmove/dest)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 1229783084848853777)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(get_global $memmove/dest)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 1229783084848853777)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.const 2459565876494606882)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.const 3689348814741910323)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.const 4919131752989213764)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 5)
|
||||||
|
)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 28)
|
||||||
|
)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 4919131679688438545)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(set_global $memmove/dest
|
||||||
|
(call $memmove/memmove
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(i32.const 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 4919131679688438545)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.const 3689348814741910323)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.const 3694152654344438852)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.add
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i64.const 4919131752989213764)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(;
|
||||||
|
[program.elements]
|
||||||
|
GLOBAL: NaN
|
||||||
|
GLOBAL: Infinity
|
||||||
|
FUNCTION_PROTOTYPE: isNaN
|
||||||
|
FUNCTION_PROTOTYPE: isFinite
|
||||||
|
FUNCTION_PROTOTYPE: clz
|
||||||
|
FUNCTION_PROTOTYPE: ctz
|
||||||
|
FUNCTION_PROTOTYPE: popcnt
|
||||||
|
FUNCTION_PROTOTYPE: rotl
|
||||||
|
FUNCTION_PROTOTYPE: rotr
|
||||||
|
FUNCTION_PROTOTYPE: abs
|
||||||
|
FUNCTION_PROTOTYPE: max
|
||||||
|
FUNCTION_PROTOTYPE: min
|
||||||
|
FUNCTION_PROTOTYPE: ceil
|
||||||
|
FUNCTION_PROTOTYPE: floor
|
||||||
|
FUNCTION_PROTOTYPE: copysign
|
||||||
|
FUNCTION_PROTOTYPE: nearest
|
||||||
|
FUNCTION_PROTOTYPE: reinterpret
|
||||||
|
FUNCTION_PROTOTYPE: sqrt
|
||||||
|
FUNCTION_PROTOTYPE: trunc
|
||||||
|
FUNCTION_PROTOTYPE: load
|
||||||
|
FUNCTION_PROTOTYPE: store
|
||||||
|
FUNCTION_PROTOTYPE: sizeof
|
||||||
|
FUNCTION_PROTOTYPE: select
|
||||||
|
FUNCTION_PROTOTYPE: unreachable
|
||||||
|
FUNCTION_PROTOTYPE: current_memory
|
||||||
|
FUNCTION_PROTOTYPE: grow_memory
|
||||||
|
FUNCTION_PROTOTYPE: changetype
|
||||||
|
FUNCTION_PROTOTYPE: assert
|
||||||
|
FUNCTION_PROTOTYPE: i8
|
||||||
|
FUNCTION_PROTOTYPE: i16
|
||||||
|
FUNCTION_PROTOTYPE: i32
|
||||||
|
FUNCTION_PROTOTYPE: i64
|
||||||
|
FUNCTION_PROTOTYPE: u8
|
||||||
|
FUNCTION_PROTOTYPE: u16
|
||||||
|
FUNCTION_PROTOTYPE: u32
|
||||||
|
FUNCTION_PROTOTYPE: u64
|
||||||
|
FUNCTION_PROTOTYPE: bool
|
||||||
|
FUNCTION_PROTOTYPE: f32
|
||||||
|
FUNCTION_PROTOTYPE: f64
|
||||||
|
FUNCTION_PROTOTYPE: isize
|
||||||
|
FUNCTION_PROTOTYPE: usize
|
||||||
|
GLOBAL: HEAP_BASE
|
||||||
|
FUNCTION_PROTOTYPE: memmove/memmove
|
||||||
|
GLOBAL: memmove/base
|
||||||
|
GLOBAL: memmove/dest
|
||||||
|
[program.exports]
|
||||||
|
|
||||||
|
;)
|
447
tests/compiler/memset.optimized.wast
Normal file
447
tests/compiler/memset.optimized.wast
Normal file
@ -0,0 +1,447 @@
|
|||||||
|
(module
|
||||||
|
(type $iiii (func (param i32 i32 i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global $memset/dest (mut i32) (i32.const 0))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 4))
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $memset/memset (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i64)
|
||||||
|
(local $5 i32)
|
||||||
|
(set_local $3
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 6)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $5
|
||||||
|
(i32.and
|
||||||
|
(i32.sub
|
||||||
|
(i32.const 0)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(tee_local $1
|
||||||
|
(i32.mul
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 16843009)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $2
|
||||||
|
(i32.and
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.const -4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 12)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 12)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 20)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 28)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 20)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(tee_local $5
|
||||||
|
(i32.add
|
||||||
|
(i32.and
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $4
|
||||||
|
(i64.or
|
||||||
|
(i64.extend_u/i32
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i64.shl
|
||||||
|
(i64.extend_u/i32
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i64.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(loop $continue|0
|
||||||
|
(if
|
||||||
|
(i32.ge_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(i64.store
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
(func $start (; 1 ;) (type $v)
|
||||||
|
(set_global $memset/dest
|
||||||
|
(get_global $HEAP_BASE)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(call $memset/memset
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(i32.load8_u
|
||||||
|
(get_global $memset/dest)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(call $memset/memset
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
(i32.const 14)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(i32.load8_u
|
||||||
|
(get_global $memset/dest)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 14)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
80
tests/compiler/memset.ts
Normal file
80
tests/compiler/memset.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
function memset(dest: usize, c: u8, n: usize): usize {
|
||||||
|
var ret = dest;
|
||||||
|
|
||||||
|
// fill head and tail wwith minimal branching
|
||||||
|
if (!n)
|
||||||
|
return ret;
|
||||||
|
store<u8>(dest, c);
|
||||||
|
store<u8>(dest + n - 1, c);
|
||||||
|
if (n <= 2)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
store<u8>(dest + 1, c);
|
||||||
|
store<u8>(dest + 2, c);
|
||||||
|
store<u8>(dest + n - 2, c);
|
||||||
|
store<u8>(dest + n - 3, c);
|
||||||
|
if (n <= 6)
|
||||||
|
return ret;
|
||||||
|
store<u8>(dest + 3, c);
|
||||||
|
store<u8>(dest + n - 4, c);
|
||||||
|
if (n <= 8)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
// advance pointer to align it at 4-byte boundary
|
||||||
|
var k: usize = -dest & 3;
|
||||||
|
dest += k;
|
||||||
|
n -= k;
|
||||||
|
n &= -4;
|
||||||
|
|
||||||
|
var c32: u32 = -1 / 255 * c;
|
||||||
|
|
||||||
|
// fill head/tail up to 28 bytes each in preparation
|
||||||
|
store<u32>(dest, c32);
|
||||||
|
store<u32>(dest + n - 4, c32);
|
||||||
|
if (n <= 8)
|
||||||
|
return ret;
|
||||||
|
store<u32>(dest + 4, c32);
|
||||||
|
store<u32>(dest + 8, c32);
|
||||||
|
store<u32>(dest + n - 12, c32);
|
||||||
|
store<u32>(dest + n - 8, c32);
|
||||||
|
if (n <= 24)
|
||||||
|
return ret;
|
||||||
|
store<u32>(dest + 12, c32);
|
||||||
|
store<u32>(dest + 16, c32);
|
||||||
|
store<u32>(dest + 20, c32);
|
||||||
|
store<u32>(dest + 24, c32);
|
||||||
|
store<u32>(dest + n - 28, c32);
|
||||||
|
store<u32>(dest + n - 24, c32);
|
||||||
|
store<u32>(dest + n - 20, c32);
|
||||||
|
store<u32>(dest + n - 16, c32);
|
||||||
|
|
||||||
|
// align to a multiple of 8
|
||||||
|
k = 24 + (dest & 4);
|
||||||
|
dest += k;
|
||||||
|
n -= k;
|
||||||
|
|
||||||
|
// copy 32 bytes each
|
||||||
|
var c64: u64 = <u64>c32 | (<u64>c32 << 32);
|
||||||
|
while (n >= 32) {
|
||||||
|
store<u64>(dest, c64);
|
||||||
|
store<u64>(dest + 8, c64);
|
||||||
|
store<u64>(dest + 16, c64);
|
||||||
|
store<u64>(dest + 24, c64);
|
||||||
|
n -= 32;
|
||||||
|
dest += 32;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dest = HEAP_BASE;
|
||||||
|
memset(dest, 1, 16);
|
||||||
|
|
||||||
|
assert(load<u8>(dest) == 1);
|
||||||
|
assert(load<u8>(dest + 15) == 1);
|
||||||
|
|
||||||
|
memset(dest + 1, 2, 14);
|
||||||
|
|
||||||
|
assert(load<u8>(dest) == 1);
|
||||||
|
assert(load<u8>(dest + 1) == 2);
|
||||||
|
assert(load<u8>(dest + 14) == 2);
|
||||||
|
assert(load<u8>(dest + 15) == 1);
|
540
tests/compiler/memset.wast
Normal file
540
tests/compiler/memset.wast
Normal file
@ -0,0 +1,540 @@
|
|||||||
|
(module
|
||||||
|
(type $iiii (func (param i32 i32 i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global $memset/dest (mut i32) (i32.const 0))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 4))
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $memset/memset (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
(local $5 i32)
|
||||||
|
(local $6 i64)
|
||||||
|
(block
|
||||||
|
(set_local $3
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 6)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(i32.store8
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(set_local $4
|
||||||
|
(i32.and
|
||||||
|
(i32.sub
|
||||||
|
(i32.const 0)
|
||||||
|
(get_local $0)
|
||||||
|
)
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.and
|
||||||
|
(get_local $2)
|
||||||
|
(i32.sub
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(set_local $5
|
||||||
|
(i32.mul
|
||||||
|
(i32.div_u
|
||||||
|
(i32.sub
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(i32.const 255)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 12)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.le_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 12)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 20)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 28)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 20)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i32.store
|
||||||
|
(i32.sub
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $2)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(set_local $4
|
||||||
|
(i32.add
|
||||||
|
(i32.const 24)
|
||||||
|
(i32.and
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(get_local $4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(set_local $6
|
||||||
|
(i64.or
|
||||||
|
(i64.extend_u/i32
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i64.shl
|
||||||
|
(i64.extend_u/i32
|
||||||
|
(get_local $5)
|
||||||
|
)
|
||||||
|
(i64.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block $break|0
|
||||||
|
(loop $continue|0
|
||||||
|
(if
|
||||||
|
(i32.ge_u
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(i64.store
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $6)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(get_local $6)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
(get_local $6)
|
||||||
|
)
|
||||||
|
(i64.store
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 24)
|
||||||
|
)
|
||||||
|
(get_local $6)
|
||||||
|
)
|
||||||
|
(set_local $2
|
||||||
|
(i32.sub
|
||||||
|
(get_local $2)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_local $0
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(br $continue|0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(return
|
||||||
|
(get_local $3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 1 ;) (type $v)
|
||||||
|
(set_global $memset/dest
|
||||||
|
(get_global $HEAP_BASE)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(call $memset/memset
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(i32.load8_u
|
||||||
|
(get_global $memset/dest)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(call $memset/memset
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
(i32.const 14)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(i32.load8_u
|
||||||
|
(get_global $memset/dest)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 14)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(i32.load8_u
|
||||||
|
(i32.add
|
||||||
|
(get_global $memset/dest)
|
||||||
|
(i32.const 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(;
|
||||||
|
[program.elements]
|
||||||
|
GLOBAL: NaN
|
||||||
|
GLOBAL: Infinity
|
||||||
|
FUNCTION_PROTOTYPE: isNaN
|
||||||
|
FUNCTION_PROTOTYPE: isFinite
|
||||||
|
FUNCTION_PROTOTYPE: clz
|
||||||
|
FUNCTION_PROTOTYPE: ctz
|
||||||
|
FUNCTION_PROTOTYPE: popcnt
|
||||||
|
FUNCTION_PROTOTYPE: rotl
|
||||||
|
FUNCTION_PROTOTYPE: rotr
|
||||||
|
FUNCTION_PROTOTYPE: abs
|
||||||
|
FUNCTION_PROTOTYPE: max
|
||||||
|
FUNCTION_PROTOTYPE: min
|
||||||
|
FUNCTION_PROTOTYPE: ceil
|
||||||
|
FUNCTION_PROTOTYPE: floor
|
||||||
|
FUNCTION_PROTOTYPE: copysign
|
||||||
|
FUNCTION_PROTOTYPE: nearest
|
||||||
|
FUNCTION_PROTOTYPE: reinterpret
|
||||||
|
FUNCTION_PROTOTYPE: sqrt
|
||||||
|
FUNCTION_PROTOTYPE: trunc
|
||||||
|
FUNCTION_PROTOTYPE: load
|
||||||
|
FUNCTION_PROTOTYPE: store
|
||||||
|
FUNCTION_PROTOTYPE: sizeof
|
||||||
|
FUNCTION_PROTOTYPE: select
|
||||||
|
FUNCTION_PROTOTYPE: unreachable
|
||||||
|
FUNCTION_PROTOTYPE: current_memory
|
||||||
|
FUNCTION_PROTOTYPE: grow_memory
|
||||||
|
FUNCTION_PROTOTYPE: changetype
|
||||||
|
FUNCTION_PROTOTYPE: assert
|
||||||
|
FUNCTION_PROTOTYPE: i8
|
||||||
|
FUNCTION_PROTOTYPE: i16
|
||||||
|
FUNCTION_PROTOTYPE: i32
|
||||||
|
FUNCTION_PROTOTYPE: i64
|
||||||
|
FUNCTION_PROTOTYPE: u8
|
||||||
|
FUNCTION_PROTOTYPE: u16
|
||||||
|
FUNCTION_PROTOTYPE: u32
|
||||||
|
FUNCTION_PROTOTYPE: u64
|
||||||
|
FUNCTION_PROTOTYPE: bool
|
||||||
|
FUNCTION_PROTOTYPE: f32
|
||||||
|
FUNCTION_PROTOTYPE: f64
|
||||||
|
FUNCTION_PROTOTYPE: isize
|
||||||
|
FUNCTION_PROTOTYPE: usize
|
||||||
|
GLOBAL: HEAP_BASE
|
||||||
|
FUNCTION_PROTOTYPE: memset/memset
|
||||||
|
GLOBAL: memset/dest
|
||||||
|
[program.exports]
|
||||||
|
|
||||||
|
;)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
var arr = changetype<i32[]>(Heap.allocate(sizeof<usize>() + 2 * sizeof<i32>()));
|
var arr = changetype<i32[]>(allocate_memory(sizeof<usize>() + 2 * sizeof<i32>()));
|
||||||
|
|
||||||
assert(arr.length == 0);
|
assert(arr.length == 0);
|
||||||
assert(arr.__capacity == 0);
|
assert(arr.__capacity == 0);
|
||||||
@ -36,7 +36,7 @@ assert(arr[0] == 43);
|
|||||||
assert(arr[1] == 44);
|
assert(arr[1] == 44);
|
||||||
assert(arr[2] == 45);
|
assert(arr[2] == 45);
|
||||||
|
|
||||||
arr.unshift(42); // see FIXME in std:array
|
arr.unshift(42);
|
||||||
|
|
||||||
assert(arr.length == 4);
|
assert(arr.length == 4);
|
||||||
assert(arr.__capacity == 4);
|
assert(arr.__capacity == 4);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,13 @@
|
|||||||
(export "memory" (memory $0))
|
(export "memory" (memory $0))
|
||||||
(start $start)
|
(start $start)
|
||||||
(func $std:array/CArray#__get (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
(func $std:array/CArray#__get (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
(i32.load
|
(i32.load
|
||||||
(i32.add
|
(i32.add
|
||||||
(get_local $0)
|
(get_local $0)
|
||||||
@ -19,6 +26,13 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
(func $std:array/CArray#__set (; 1 ;) (type $iiiv) (param $0 i32) (param $1 i32) (param $2 i32)
|
(func $std:array/CArray#__set (; 1 ;) (type $iiiv) (param $0 i32) (param $1 i32) (param $2 i32)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
(i32.store
|
(i32.store
|
||||||
(i32.add
|
(i32.add
|
||||||
(get_local $0)
|
(get_local $0)
|
||||||
|
@ -8,6 +8,13 @@
|
|||||||
(export "memory" (memory $0))
|
(export "memory" (memory $0))
|
||||||
(start $start)
|
(start $start)
|
||||||
(func $std:array/CArray#__get (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
(func $std:array/CArray#__get (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
(return
|
(return
|
||||||
(i32.load
|
(i32.load
|
||||||
(i32.add
|
(i32.add
|
||||||
@ -21,6 +28,13 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
(func $std:array/CArray#__set (; 1 ;) (type $iiiv) (param $0 i32) (param $1 i32) (param $2 i32)
|
(func $std:array/CArray#__set (; 1 ;) (type $iiiv) (param $0 i32) (param $1 i32) (param $2 i32)
|
||||||
|
(if
|
||||||
|
(i32.lt_s
|
||||||
|
(get_local $1)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
(i32.store
|
(i32.store
|
||||||
(i32.add
|
(i32.add
|
||||||
(get_local $0)
|
(get_local $0)
|
||||||
@ -247,16 +261,17 @@
|
|||||||
GLOBAL: std:heap/ALIGN_SIZE
|
GLOBAL: std:heap/ALIGN_SIZE
|
||||||
GLOBAL: std:heap/ALIGN_MASK
|
GLOBAL: std:heap/ALIGN_MASK
|
||||||
GLOBAL: std:heap/HEAP_OFFSET
|
GLOBAL: std:heap/HEAP_OFFSET
|
||||||
CLASS_PROTOTYPE: std:heap/Heap
|
FUNCTION_PROTOTYPE: std:heap/allocate_memory
|
||||||
CLASS_PROTOTYPE: Heap
|
FUNCTION_PROTOTYPE: allocate_memory
|
||||||
PROPERTY: std:heap/Heap.used
|
FUNCTION_PROTOTYPE: std:heap/free_memory
|
||||||
PROPERTY: std:heap/Heap.free
|
FUNCTION_PROTOTYPE: free_memory
|
||||||
PROPERTY: std:heap/Heap.size
|
FUNCTION_PROTOTYPE: std:heap/copy_memory
|
||||||
FUNCTION_PROTOTYPE: std:heap/Heap.allocate
|
FUNCTION_PROTOTYPE: std:heap/move_memory
|
||||||
FUNCTION_PROTOTYPE: std:heap/Heap.dispose
|
FUNCTION_PROTOTYPE: move_memory
|
||||||
FUNCTION_PROTOTYPE: std:heap/Heap.copy
|
FUNCTION_PROTOTYPE: std:heap/set_memory
|
||||||
FUNCTION_PROTOTYPE: std:heap/Heap.fill
|
FUNCTION_PROTOTYPE: set_memory
|
||||||
FUNCTION_PROTOTYPE: std:heap/Heap.compare
|
FUNCTION_PROTOTYPE: std:heap/compare_memory
|
||||||
|
FUNCTION_PROTOTYPE: compare_memory
|
||||||
CLASS_PROTOTYPE: std:map/Map
|
CLASS_PROTOTYPE: std:map/Map
|
||||||
CLASS_PROTOTYPE: Map
|
CLASS_PROTOTYPE: Map
|
||||||
CLASS_PROTOTYPE: std:regexp/RegExp
|
CLASS_PROTOTYPE: std:regexp/RegExp
|
||||||
@ -277,7 +292,11 @@
|
|||||||
CLASS_PROTOTYPE: std:array/CArray
|
CLASS_PROTOTYPE: std:array/CArray
|
||||||
CLASS_PROTOTYPE: std:error/Error
|
CLASS_PROTOTYPE: std:error/Error
|
||||||
CLASS_PROTOTYPE: std:error/RangeError
|
CLASS_PROTOTYPE: std:error/RangeError
|
||||||
CLASS_PROTOTYPE: std:heap/Heap
|
FUNCTION_PROTOTYPE: std:heap/allocate_memory
|
||||||
|
FUNCTION_PROTOTYPE: std:heap/free_memory
|
||||||
|
FUNCTION_PROTOTYPE: std:heap/move_memory
|
||||||
|
FUNCTION_PROTOTYPE: std:heap/set_memory
|
||||||
|
FUNCTION_PROTOTYPE: std:heap/compare_memory
|
||||||
CLASS_PROTOTYPE: std:map/Map
|
CLASS_PROTOTYPE: std:map/Map
|
||||||
CLASS_PROTOTYPE: std:regexp/RegExp
|
CLASS_PROTOTYPE: std:regexp/RegExp
|
||||||
CLASS_PROTOTYPE: std:set/Set
|
CLASS_PROTOTYPE: std:set/Set
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,21 @@
|
|||||||
const size: usize = 42;
|
const size: usize = 42;
|
||||||
let ptr1: usize = Heap.allocate(size);
|
let ptr1: usize = allocate_memory(size);
|
||||||
let ptr2: usize = Heap.allocate(size);
|
let ptr2: usize = allocate_memory(size);
|
||||||
|
|
||||||
assert(ptr1 != ptr2);
|
assert(ptr1 != ptr2);
|
||||||
|
|
||||||
Heap.fill(ptr1, 0x12, size);
|
set_memory(ptr1, 0x12, size);
|
||||||
|
|
||||||
let i: usize;
|
let i: usize;
|
||||||
for (i = 0; i < size; ++i)
|
for (i = 0; i < size; ++i)
|
||||||
assert(load<u8>(ptr1 + i) == 0x12);
|
assert(load<u8>(ptr1 + i) == 0x12);
|
||||||
|
|
||||||
Heap.copy(ptr2, ptr1, size);
|
move_memory(ptr2, ptr1, size);
|
||||||
|
|
||||||
for (i = 0; i < size; ++i)
|
for (i = 0; i < size; ++i)
|
||||||
assert(load<u8>(ptr2 + i) == 0x12);
|
assert(load<u8>(ptr2 + i) == 0x12);
|
||||||
|
|
||||||
assert(Heap.compare(ptr1, ptr2, size) == 0);
|
assert(compare_memory(ptr1, ptr2, size) == 0);
|
||||||
|
|
||||||
Heap.dispose(ptr1);
|
free_memory(ptr1);
|
||||||
Heap.dispose(ptr2);
|
free_memory(ptr2);
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user