hakojs
Version:
A secure, embeddable JavaScript engine that runs untrusted code inside WebAssembly sandboxes with fine-grained permissions and resource limits
166 lines (164 loc) • 5.04 kB
JavaScript
// src/mem/memory.ts
class MemoryManager {
exports = null;
encoder = new TextEncoder;
decoder = new TextDecoder;
setExports(exports) {
this.exports = exports;
}
checkExports() {
if (!this.exports) {
throw new Error("Exports not set on MemoryManager");
}
return this.exports;
}
allocateMemory(ctx, size) {
if (size <= 0) {
throw new Error("Size must be greater than 0");
}
const exports = this.checkExports();
const ptr = exports.HAKO_Malloc(ctx, size);
if (ptr === 0) {
throw new Error(`Failed to allocate ${size} bytes of memory`);
}
return ptr;
}
allocateRuntimeMemory(rt, size) {
if (size <= 0) {
throw new Error("Size must be greater than 0");
}
const exports = this.checkExports();
const ptr = exports.HAKO_RuntimeMalloc(rt, size);
if (ptr === 0) {
throw new Error(`Failed to allocate ${size} bytes of memory`);
}
return ptr;
}
freeMemory(ctx, ptr) {
if (ptr !== 0) {
const exports = this.checkExports();
exports.HAKO_Free(ctx, ptr);
}
}
freeRuntimeMemory(rt, ptr) {
if (ptr !== 0) {
const exports = this.checkExports();
exports.HAKO_RuntimeFree(rt, ptr);
}
}
writeBytes(ctx, bytes) {
const exports = this.checkExports();
const ptr = this.allocateMemory(ctx, bytes.byteLength);
const memory = new Uint8Array(exports.memory.buffer);
memory.set(bytes.subarray(0, bytes.byteLength), ptr);
return ptr;
}
allocateString(ctx, str) {
const exports = this.checkExports();
const bytes = this.encoder.encode(str);
const ptr = this.allocateMemory(ctx, bytes.byteLength + 1);
const memory = new Uint8Array(exports.memory.buffer);
memory.set(bytes, ptr);
memory[ptr + bytes.length] = 0;
return ptr;
}
copy(offset, length) {
const exports = this.checkExports();
const memory = new Uint8Array(exports.memory.buffer);
return memory.slice(offset, offset + length);
}
slice(offset, length) {
const exports = this.checkExports();
const memory = new Uint8Array(exports.memory.buffer);
return memory.subarray(offset, offset + length);
}
writeNullTerminatedString(ctx, str) {
const exports = this.checkExports();
const bytes = this.encoder.encode(str);
const ptr = this.allocateMemory(ctx, bytes.byteLength + 1);
const memory = new Uint8Array(exports.memory.buffer);
memory.set(bytes, ptr);
memory[ptr + bytes.length] = 0;
return { pointer: ptr, length: bytes.length + 1 };
}
readString(ptr) {
if (ptr === 0)
return "";
const exports = this.checkExports();
const memory = new Uint8Array(exports.memory.buffer);
let end = ptr;
while (memory[end] !== 0)
end++;
return this.decoder.decode(memory.subarray(ptr, end));
}
freeCString(ctx, ptr) {
if (ptr !== 0) {
const exports = this.checkExports();
exports.HAKO_FreeCString(ctx, ptr);
}
}
freeValuePointer(ctx, ptr) {
if (ptr !== 0) {
const exports = this.checkExports();
exports.HAKO_FreeValuePointer(ctx, ptr);
}
}
freeValuePointerRuntime(rt, ptr) {
if (ptr !== 0) {
const exports = this.checkExports();
exports.HAKO_FreeValuePointerRuntime(rt, ptr);
}
}
dupValuePointer(ctx, ptr) {
const exports = this.checkExports();
return exports.HAKO_DupValuePointer(ctx, ptr);
}
newArrayBuffer(ctx, data) {
const exports = this.checkExports();
if (data.byteLength === 0) {
return exports.HAKO_NewArrayBuffer(ctx, 0, 0);
}
const bufPtr = this.allocateMemory(ctx, data.byteLength);
const memory = new Uint8Array(exports.memory.buffer);
memory.set(data, bufPtr);
return exports.HAKO_NewArrayBuffer(ctx, bufPtr, data.byteLength);
}
allocatePointerArray(ctx, count) {
return this.allocateMemory(ctx, count * 4);
}
allocateRuntimePointerArray(rt, count) {
return this.allocateRuntimeMemory(rt, count * 4);
}
writePointerToArray(arrayPtr, index, value) {
const exports = this.checkExports();
const view = new DataView(exports.memory.buffer);
const ptr = arrayPtr + index * 4;
view.setUint32(ptr, value, true);
return ptr;
}
readPointerFromArray(arrayPtr, index) {
const exports = this.checkExports();
const view = new DataView(exports.memory.buffer);
return view.getUint32(arrayPtr + index * 4, true);
}
readPointer(address) {
const exports = this.checkExports();
const view = new DataView(exports.memory.buffer);
return view.getUint32(address, true);
}
readUint32(address) {
const exports = this.checkExports();
const view = new DataView(exports.memory.buffer);
return view.getUint32(address, true);
}
writeUint32(address, value) {
const exports = this.checkExports();
const view = new DataView(exports.memory.buffer);
view.setUint32(address, value, true);
}
}
export {
MemoryManager
};
//# debugId=BC1EDCC960093E7464756E2164756E21
//# sourceMappingURL=memory.js.map