- Add GETTING_STARTED.md with quick start guide and development modes - Add INSTALL.sh automated installation script - Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md - Add QUICK_REFERENCE.md for common commands - Add SETUP_GUIDE.md with detailed setup instructions - Update README.md with improved project overview - Add did-wallet app dependencies and node_modules
418 lines
16 KiB
JavaScript
418 lines
16 KiB
JavaScript
"use strict";
|
|
|
|
// Runtime header offsets
|
|
const ID_OFFSET = -8;
|
|
const SIZE_OFFSET = -4;
|
|
|
|
// Runtime ids
|
|
const ARRAYBUFFER_ID = 0;
|
|
const STRING_ID = 1;
|
|
const ARRAYBUFFERVIEW_ID = 2;
|
|
|
|
// Runtime type information
|
|
const ARRAYBUFFERVIEW = 1 << 0;
|
|
const ARRAY = 1 << 1;
|
|
const SET = 1 << 2;
|
|
const MAP = 1 << 3;
|
|
const VAL_ALIGN_OFFSET = 5;
|
|
const VAL_ALIGN = 1 << VAL_ALIGN_OFFSET;
|
|
const VAL_SIGNED = 1 << 10;
|
|
const VAL_FLOAT = 1 << 11;
|
|
const VAL_NULLABLE = 1 << 12;
|
|
const VAL_MANAGED = 1 << 13;
|
|
const KEY_ALIGN_OFFSET = 14;
|
|
const KEY_ALIGN = 1 << KEY_ALIGN_OFFSET;
|
|
const KEY_SIGNED = 1 << 19;
|
|
const KEY_FLOAT = 1 << 20;
|
|
const KEY_NULLABLE = 1 << 21;
|
|
const KEY_MANAGED = 1 << 22;
|
|
|
|
// Array(BufferView) layout
|
|
const ARRAYBUFFERVIEW_BUFFER_OFFSET = 0;
|
|
const ARRAYBUFFERVIEW_DATASTART_OFFSET = 4;
|
|
const ARRAYBUFFERVIEW_DATALENGTH_OFFSET = 8;
|
|
const ARRAYBUFFERVIEW_SIZE = 12;
|
|
const ARRAY_LENGTH_OFFSET = 12;
|
|
const ARRAY_SIZE = 16;
|
|
|
|
const BIGINT = typeof BigUint64Array !== "undefined";
|
|
const THIS = Symbol();
|
|
const CHUNKSIZE = 1024;
|
|
|
|
/** Gets a string from an U32 and an U16 view on a memory. */
|
|
function getStringImpl(buffer, ptr) {
|
|
const U32 = new Uint32Array(buffer);
|
|
const U16 = new Uint16Array(buffer);
|
|
var length = U32[(ptr + SIZE_OFFSET) >>> 2] >>> 1;
|
|
var offset = ptr >>> 1;
|
|
if (length <= CHUNKSIZE) return String.fromCharCode.apply(String, U16.subarray(offset, offset + length));
|
|
const parts = [];
|
|
do {
|
|
const last = U16[offset + CHUNKSIZE - 1];
|
|
const size = last >= 0xD800 && last < 0xDC00 ? CHUNKSIZE - 1 : CHUNKSIZE;
|
|
parts.push(String.fromCharCode.apply(String, U16.subarray(offset, offset += size)));
|
|
length -= size;
|
|
} while (length > CHUNKSIZE);
|
|
return parts.join("") + String.fromCharCode.apply(String, U16.subarray(offset, offset + length));
|
|
}
|
|
|
|
/** Prepares the base module prior to instantiation. */
|
|
function preInstantiate(imports) {
|
|
const baseModule = {};
|
|
|
|
function getString(memory, ptr) {
|
|
if (!memory) return "<yet unknown>";
|
|
return getStringImpl(memory.buffer, ptr);
|
|
}
|
|
|
|
// add common imports used by stdlib for convenience
|
|
const env = (imports.env = imports.env || {});
|
|
env.abort = env.abort || function abort(mesg, file, line, colm) {
|
|
const memory = baseModule.memory || env.memory; // prefer exported, otherwise try imported
|
|
throw Error("abort: " + getString(memory, mesg) + " at " + getString(memory, file) + ":" + line + ":" + colm);
|
|
}
|
|
env.trace = env.trace || function trace(mesg, n) {
|
|
const memory = baseModule.memory || env.memory;
|
|
console.log("trace: " + getString(memory, mesg) + (n ? " " : "") + Array.prototype.slice.call(arguments, 2, 2 + n).join(", "));
|
|
}
|
|
imports.Math = imports.Math || Math;
|
|
imports.Date = imports.Date || Date;
|
|
|
|
return baseModule;
|
|
}
|
|
|
|
/** Prepares the final module once instantiation is complete. */
|
|
function postInstantiate(baseModule, instance) {
|
|
const rawExports = instance.exports;
|
|
const memory = rawExports.memory;
|
|
const table = rawExports.table;
|
|
const alloc = rawExports["__alloc"];
|
|
const retain = rawExports["__retain"];
|
|
const rttiBase = rawExports["__rtti_base"] || ~0; // oob if not present
|
|
|
|
/** Gets the runtime type info for the given id. */
|
|
function getInfo(id) {
|
|
const U32 = new Uint32Array(memory.buffer);
|
|
const count = U32[rttiBase >>> 2];
|
|
if ((id >>>= 0) >= count) throw Error("invalid id: " + id);
|
|
return U32[(rttiBase + 4 >>> 2) + id * 2];
|
|
}
|
|
|
|
/** Gets the runtime base id for the given id. */
|
|
function getBase(id) {
|
|
const U32 = new Uint32Array(memory.buffer);
|
|
const count = U32[rttiBase >>> 2];
|
|
if ((id >>>= 0) >= count) throw Error("invalid id: " + id);
|
|
return U32[(rttiBase + 4 >>> 2) + id * 2 + 1];
|
|
}
|
|
|
|
/** Gets the runtime alignment of a collection's values. */
|
|
function getValueAlign(info) {
|
|
return 31 - Math.clz32((info >>> VAL_ALIGN_OFFSET) & 31); // -1 if none
|
|
}
|
|
|
|
/** Gets the runtime alignment of a collection's keys. */
|
|
function getKeyAlign(info) {
|
|
return 31 - Math.clz32((info >>> KEY_ALIGN_OFFSET) & 31); // -1 if none
|
|
}
|
|
|
|
/** Allocates a new string in the module's memory and returns its retained pointer. */
|
|
function __allocString(str) {
|
|
const length = str.length;
|
|
const ptr = alloc(length << 1, STRING_ID);
|
|
const U16 = new Uint16Array(memory.buffer);
|
|
for (var i = 0, p = ptr >>> 1; i < length; ++i) U16[p + i] = str.charCodeAt(i);
|
|
return ptr;
|
|
}
|
|
|
|
baseModule.__allocString = __allocString;
|
|
|
|
/** Reads a string from the module's memory by its pointer. */
|
|
function __getString(ptr) {
|
|
const buffer = memory.buffer;
|
|
const id = new Uint32Array(buffer)[ptr + ID_OFFSET >>> 2];
|
|
if (id !== STRING_ID) throw Error("not a string: " + ptr);
|
|
return getStringImpl(buffer, ptr);
|
|
}
|
|
|
|
baseModule.__getString = __getString;
|
|
|
|
/** Gets the view matching the specified alignment, signedness and floatness. */
|
|
function getView(alignLog2, signed, float) {
|
|
const buffer = memory.buffer;
|
|
if (float) {
|
|
switch (alignLog2) {
|
|
case 2: return new Float32Array(buffer);
|
|
case 3: return new Float64Array(buffer);
|
|
}
|
|
} else {
|
|
switch (alignLog2) {
|
|
case 0: return new (signed ? Int8Array : Uint8Array)(buffer);
|
|
case 1: return new (signed ? Int16Array : Uint16Array)(buffer);
|
|
case 2: return new (signed ? Int32Array : Uint32Array)(buffer);
|
|
case 3: return new (signed ? BigInt64Array : BigUint64Array)(buffer);
|
|
}
|
|
}
|
|
throw Error("unsupported align: " + alignLog2);
|
|
}
|
|
|
|
/** Allocates a new array in the module's memory and returns its retained pointer. */
|
|
function __allocArray(id, values) {
|
|
const info = getInfo(id);
|
|
if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + " @ " + info);
|
|
const align = getValueAlign(info);
|
|
const length = values.length;
|
|
const buf = alloc(length << align, ARRAYBUFFER_ID);
|
|
const arr = alloc(info & ARRAY ? ARRAY_SIZE : ARRAYBUFFERVIEW_SIZE, id);
|
|
const U32 = new Uint32Array(memory.buffer);
|
|
U32[arr + ARRAYBUFFERVIEW_BUFFER_OFFSET >>> 2] = retain(buf);
|
|
U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2] = buf;
|
|
U32[arr + ARRAYBUFFERVIEW_DATALENGTH_OFFSET >>> 2] = length << align;
|
|
if (info & ARRAY) U32[arr + ARRAY_LENGTH_OFFSET >>> 2] = length;
|
|
const view = getView(align, info & VAL_SIGNED, info & VAL_FLOAT);
|
|
if (info & VAL_MANAGED) {
|
|
for (let i = 0; i < length; ++i) view[(buf >>> align) + i] = retain(values[i]);
|
|
} else {
|
|
view.set(values, buf >>> align);
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
baseModule.__allocArray = __allocArray;
|
|
|
|
/** Gets a live view on an array's values in the module's memory. Infers the array type from RTTI. */
|
|
function __getArrayView(arr) {
|
|
const U32 = new Uint32Array(memory.buffer);
|
|
const id = U32[arr + ID_OFFSET >>> 2];
|
|
const info = getInfo(id);
|
|
if (!(info & ARRAYBUFFERVIEW)) throw Error("not an array: " + id);
|
|
const align = getValueAlign(info);
|
|
var buf = U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
|
|
const length = info & ARRAY
|
|
? U32[arr + ARRAY_LENGTH_OFFSET >>> 2]
|
|
: U32[buf + SIZE_OFFSET >>> 2] >>> align;
|
|
return getView(align, info & VAL_SIGNED, info & VAL_FLOAT)
|
|
.subarray(buf >>>= align, buf + length);
|
|
}
|
|
|
|
baseModule.__getArrayView = __getArrayView;
|
|
|
|
/** Copies an array's values from the module's memory. Infers the array type from RTTI. */
|
|
function __getArray(arr) {
|
|
const input = __getArrayView(arr);
|
|
const len = input.length;
|
|
const out = new Array(len);
|
|
for (let i = 0; i < len; i++) out[i] = input[i];
|
|
return out;
|
|
}
|
|
|
|
baseModule.__getArray = __getArray;
|
|
|
|
/** Copies an ArrayBuffer's value from the module's memory. */
|
|
function __getArrayBuffer(ptr) {
|
|
const buffer = memory.buffer;
|
|
const length = new Uint32Array(buffer)[ptr + SIZE_OFFSET >>> 2];
|
|
return buffer.slice(ptr, ptr + length);
|
|
}
|
|
|
|
baseModule.__getArrayBuffer = __getArrayBuffer;
|
|
|
|
/** Copies a typed array's values from the module's memory. */
|
|
function getTypedArray(Type, alignLog2, ptr) {
|
|
return new Type(getTypedArrayView(Type, alignLog2, ptr));
|
|
}
|
|
|
|
/** Gets a live view on a typed array's values in the module's memory. */
|
|
function getTypedArrayView(Type, alignLog2, ptr) {
|
|
const buffer = memory.buffer;
|
|
const U32 = new Uint32Array(buffer);
|
|
const bufPtr = U32[ptr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
|
|
return new Type(buffer, bufPtr, U32[bufPtr + SIZE_OFFSET >>> 2] >>> alignLog2);
|
|
}
|
|
|
|
baseModule.__getInt8Array = getTypedArray.bind(null, Int8Array, 0);
|
|
baseModule.__getInt8ArrayView = getTypedArrayView.bind(null, Int8Array, 0);
|
|
baseModule.__getUint8Array = getTypedArray.bind(null, Uint8Array, 0);
|
|
baseModule.__getUint8ArrayView = getTypedArrayView.bind(null, Uint8Array, 0);
|
|
baseModule.__getUint8ClampedArray = getTypedArray.bind(null, Uint8ClampedArray, 0);
|
|
baseModule.__getUint8ClampedArrayView = getTypedArrayView.bind(null, Uint8ClampedArray, 0);
|
|
baseModule.__getInt16Array = getTypedArray.bind(null, Int16Array, 1);
|
|
baseModule.__getInt16ArrayView = getTypedArrayView.bind(null, Int16Array, 1);
|
|
baseModule.__getUint16Array = getTypedArray.bind(null, Uint16Array, 1);
|
|
baseModule.__getUint16ArrayView = getTypedArrayView.bind(null, Uint16Array, 1);
|
|
baseModule.__getInt32Array = getTypedArray.bind(null, Int32Array, 2);
|
|
baseModule.__getInt32ArrayView = getTypedArrayView.bind(null, Int32Array, 2);
|
|
baseModule.__getUint32Array = getTypedArray.bind(null, Uint32Array, 2);
|
|
baseModule.__getUint32ArrayView = getTypedArrayView.bind(null, Uint32Array, 2);
|
|
if (BIGINT) {
|
|
baseModule.__getInt64Array = getTypedArray.bind(null, BigInt64Array, 3);
|
|
baseModule.__getInt64ArrayView = getTypedArrayView.bind(null, BigInt64Array, 3);
|
|
baseModule.__getUint64Array = getTypedArray.bind(null, BigUint64Array, 3);
|
|
baseModule.__getUint64ArrayView = getTypedArrayView.bind(null, BigUint64Array, 3);
|
|
}
|
|
baseModule.__getFloat32Array = getTypedArray.bind(null, Float32Array, 2);
|
|
baseModule.__getFloat32ArrayView = getTypedArrayView.bind(null, Float32Array, 2);
|
|
baseModule.__getFloat64Array = getTypedArray.bind(null, Float64Array, 3);
|
|
baseModule.__getFloat64ArrayView = getTypedArrayView.bind(null, Float64Array, 3);
|
|
|
|
/** Tests whether an object is an instance of the class represented by the specified base id. */
|
|
function __instanceof(ptr, baseId) {
|
|
const U32 = new Uint32Array(memory.buffer);
|
|
var id = U32[(ptr + ID_OFFSET) >>> 2];
|
|
if (id <= U32[rttiBase >>> 2]) {
|
|
do if (id == baseId) return true;
|
|
while (id = getBase(id));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
baseModule.__instanceof = __instanceof;
|
|
|
|
// Pull basic exports to baseModule so code in preInstantiate can use them
|
|
baseModule.memory = baseModule.memory || memory;
|
|
baseModule.table = baseModule.table || table;
|
|
|
|
// Demangle exports and provide the usual utility on the prototype
|
|
return demangle(rawExports, baseModule);
|
|
}
|
|
|
|
function isResponse(o) {
|
|
return typeof Response !== "undefined" && o instanceof Response;
|
|
}
|
|
|
|
/** Asynchronously instantiates an AssemblyScript module from anything that can be instantiated. */
|
|
async function instantiate(source, imports) {
|
|
if (isResponse(source = await source)) return instantiateStreaming(source, imports);
|
|
return postInstantiate(
|
|
preInstantiate(imports || (imports = {})),
|
|
await WebAssembly.instantiate(
|
|
source instanceof WebAssembly.Module
|
|
? source
|
|
: await WebAssembly.compile(source),
|
|
imports
|
|
)
|
|
);
|
|
}
|
|
|
|
exports.instantiate = instantiate;
|
|
|
|
/** Synchronously instantiates an AssemblyScript module from a WebAssembly.Module or binary buffer. */
|
|
function instantiateSync(source, imports) {
|
|
return postInstantiate(
|
|
preInstantiate(imports || (imports = {})),
|
|
new WebAssembly.Instance(
|
|
source instanceof WebAssembly.Module
|
|
? source
|
|
: new WebAssembly.Module(source),
|
|
imports
|
|
)
|
|
)
|
|
}
|
|
|
|
exports.instantiateSync = instantiateSync;
|
|
|
|
/** Asynchronously instantiates an AssemblyScript module from a response, i.e. as obtained by `fetch`. */
|
|
async function instantiateStreaming(source, imports) {
|
|
if (!WebAssembly.instantiateStreaming) {
|
|
return instantiate(
|
|
isResponse(source = await source)
|
|
? source.arrayBuffer()
|
|
: source,
|
|
imports
|
|
);
|
|
}
|
|
return postInstantiate(
|
|
preInstantiate(imports || (imports = {})),
|
|
(await WebAssembly.instantiateStreaming(source, imports)).instance
|
|
);
|
|
}
|
|
|
|
exports.instantiateStreaming = instantiateStreaming;
|
|
|
|
/** Demangles an AssemblyScript module's exports to a friendly object structure. */
|
|
function demangle(exports, baseModule) {
|
|
var module = baseModule ? Object.create(baseModule) : {};
|
|
var setArgumentsLength = exports["__argumentsLength"]
|
|
? function(length) { exports["__argumentsLength"].value = length; }
|
|
: exports["__setArgumentsLength"] || exports["__setargc"] || function() {};
|
|
for (let internalName in exports) {
|
|
if (!Object.prototype.hasOwnProperty.call(exports, internalName)) continue;
|
|
const elem = exports[internalName];
|
|
let parts = internalName.split(".");
|
|
let curr = module;
|
|
while (parts.length > 1) {
|
|
let part = parts.shift();
|
|
if (!Object.prototype.hasOwnProperty.call(curr, part)) curr[part] = {};
|
|
curr = curr[part];
|
|
}
|
|
let name = parts[0];
|
|
let hash = name.indexOf("#");
|
|
if (hash >= 0) {
|
|
let className = name.substring(0, hash);
|
|
let classElem = curr[className];
|
|
if (typeof classElem === "undefined" || !classElem.prototype) {
|
|
let ctor = function(...args) {
|
|
return ctor.wrap(ctor.prototype.constructor(0, ...args));
|
|
};
|
|
ctor.prototype = {
|
|
valueOf: function valueOf() {
|
|
return this[THIS];
|
|
}
|
|
};
|
|
ctor.wrap = function(thisValue) {
|
|
return Object.create(ctor.prototype, { [THIS]: { value: thisValue, writable: false } });
|
|
};
|
|
if (classElem) Object.getOwnPropertyNames(classElem).forEach(name =>
|
|
Object.defineProperty(ctor, name, Object.getOwnPropertyDescriptor(classElem, name))
|
|
);
|
|
curr[className] = ctor;
|
|
}
|
|
name = name.substring(hash + 1);
|
|
curr = curr[className].prototype;
|
|
if (/^(get|set):/.test(name)) {
|
|
if (!Object.prototype.hasOwnProperty.call(curr, name = name.substring(4))) {
|
|
let getter = exports[internalName.replace("set:", "get:")];
|
|
let setter = exports[internalName.replace("get:", "set:")];
|
|
Object.defineProperty(curr, name, {
|
|
get: function() { return getter(this[THIS]); },
|
|
set: function(value) { setter(this[THIS], value); },
|
|
enumerable: true
|
|
});
|
|
}
|
|
} else {
|
|
if (name === 'constructor') {
|
|
(curr[name] = (...args) => {
|
|
setArgumentsLength(args.length);
|
|
return elem(...args);
|
|
}).original = elem;
|
|
} else { // instance method
|
|
(curr[name] = function(...args) { // !
|
|
setArgumentsLength(args.length);
|
|
return elem(this[THIS], ...args);
|
|
}).original = elem;
|
|
}
|
|
}
|
|
} else {
|
|
if (/^(get|set):/.test(name)) {
|
|
if (!Object.prototype.hasOwnProperty.call(curr, name = name.substring(4))) {
|
|
Object.defineProperty(curr, name, {
|
|
get: exports[internalName.replace("set:", "get:")],
|
|
set: exports[internalName.replace("get:", "set:")],
|
|
enumerable: true
|
|
});
|
|
}
|
|
} else if (typeof elem === "function" && elem !== setArgumentsLength) {
|
|
(curr[name] = (...args) => {
|
|
setArgumentsLength(args.length);
|
|
return elem(...args);
|
|
}).original = elem;
|
|
} else {
|
|
curr[name] = elem;
|
|
}
|
|
}
|
|
}
|
|
return module;
|
|
}
|
|
|
|
exports.demangle = demangle;
|