diff --git a/assembly.d.ts b/assembly.d.ts index 50bf55c0..c658213b 100644 --- a/assembly.d.ts +++ b/assembly.d.ts @@ -78,6 +78,8 @@ declare function unreachable(): any; // sic declare const NaN: f32 | f64; /** Positive infinity as a 32-bit or 64-bit float depending on context. */ declare const Infinity: f32 | f64; +/** Heap start offset. */ +declare const HEAP_START: usize; /** Determines the byte size of the specified core or class type. Compiles to a constant. */ declare function sizeof(): usize; /** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */ @@ -100,6 +102,13 @@ declare function struct(): any; // Standard library (not yet implemented) -/// -/// /// + +interface Array {} +interface Boolean {} +interface Function {} +interface IArguments {} +interface Number {} +interface Object {} +interface RegExp {} +interface String {} diff --git a/assembly.json b/assembly.json new file mode 100644 index 00000000..ad58b722 --- /dev/null +++ b/assembly.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig-base.json", + "compilerOptions": { + "target": "esnext", + "noLib": true, + "types": [], + "rootDirs": [ + "./std/assembly", + "./node_modules" + ] + }, + "files": [ + "./assembly.d.ts" + ] +} diff --git a/package.json b/package.json index 5ae278e2..acd25312 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,13 @@ "scripts": { "build": "webpack", "clean": "rm dist/assemblyscript.*", - "test:parser": "ts-node -P src tests/parser", - "test:compiler": "ts-node -P src tests/compiler", - "test": "npm run test:parser && npm run test:compiler" + "test:config": "npm run test:config:assembly --scripts-prepend-node-path && npm run test:config:portable --scripts-prepend-node-path && npm run test:config:src --scripts-prepend-node-path", + "test:config:assembly": "tsc --noEmit -p std/assembly --diagnostics --listFiles", + "test:config:portable": "tsc --noEmit -p std/portable --diagnostics --listFiles", + "test:config:src": "tsc --noEmit -p src --diagnostics --listFiles", + "test:parser": "node tests/parser", + "test:compiler": "node tests/compiler", + "test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path" }, "files": [ "assembly.d.ts", diff --git a/portable-assembly.d.ts b/portable-assembly.d.ts index 04c8e4d0..709ab089 100644 --- a/portable-assembly.d.ts +++ b/portable-assembly.d.ts @@ -44,5 +44,100 @@ declare function trunc(value: T): T; /** Emits an unreachable operation that results in a runtime error when executed. */ declare function unreachable(): any; // sic +/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */ +declare function changetype(value: T1): T2; /** Traps if the specified value evaluates to `false`. */ declare function assert(isTrue: bool): void; + +// Portable standard library +// Everything marked @deprecated is a temporary filler. Do not use. + +declare const NaN: f32 | f64; +declare const Infinity: f32 | f64; + +declare class Array { + [key: number]: T; + length: i32; + constructor(capacity?: i32); + push(value: T): void; + pop(): T; + join(delim: string): string; + slice(from: i32, to?: i32): T[]; + splice(index: i32, count: i32): T[]; +} + +declare class Uint8Array extends Array {} +declare class Uint16Array extends Array {} +declare class Uint32Array extends Array {} +declare class Int8Array extends Array {} +declare class Int16Array extends Array {} +declare class Int32Array extends Array {} + +declare class String { + static fromCharCode(ls: i32, hs?: i32): string; + readonly length: i32; + indexOf(subject: string): i32; + charCodeAt(index: i32): i32; + substring(from: i32, to?: i32): string; + startsWith(subject: string): bool; + endsWith(subject: string): bool; + replace(search: string, replacement: string): string; +} + +declare class Boolean {} + +declare class Number { + toString(radix: i32): string; +} + +declare class Object {} + +declare class Function { + /** @deprecated */ + apply(subject: any): any; +} + +declare class RegExp {} + +declare interface IArguments {} + +declare class Error { + constructor(message: string); + message: string; +} + +declare class Symbol { + static iterator: symbol; +} + +declare class Set { + constructor(entries?: T[]); + add(value: T): void; + has(value: T): bool; + clear(): void; + [Symbol.iterator](): Iterator; +} + +declare class Map { + constructor(entries?: [K, V][]); + set(key: K, value: V): void; + has(key: K): bool; + get(key: K): V | null; + clear(): void; + [Symbol.iterator](): Iterator<[K, V]>; +} + +declare interface Iterator {} + +declare namespace JSON { + /** @deprecated */ + function stringify(subject: any): string; +} + +declare namespace console { + /** @deprecated */ + function log(message: string): void; +} + +/** @deprecated */ +declare function parseFloat(str: string): f64; diff --git a/portable-assembly.js b/portable-assembly.js index 1c0e6c1f..7d34b6d7 100644 --- a/portable-assembly.js +++ b/portable-assembly.js @@ -27,3 +27,4 @@ AssertionError.prototype.name = "AssertionError"; AssertionError.prototype.message = "assertion failed"; globalScope["assert"] = function assert(isTrue) { if (!isTrue) throw new AssertionError(); }; +globalScope["changetype"] = function changetype(value) { return value; } diff --git a/portable-assembly.json b/portable-assembly.json new file mode 100644 index 00000000..18d3f88a --- /dev/null +++ b/portable-assembly.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig-base.json", + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "downlevelIteration": true, + "preserveConstEnums": true, + "noLib": true, + "types": [], + "rootDirs": [ + "./std/portable", + "./node_modules" + ], + "allowJs": true + }, + "files": [ + "./portable-assembly.d.ts", + "./portable-assembly.js", + "./std/portable/heap.d.ts", + "./std/portable/heap.js" + ] +} diff --git a/src/ast.ts b/src/ast.ts index 31ff983d..ffdd4b77 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -475,7 +475,7 @@ export class FloatLiteralExpression extends LiteralExpression { value: f64; serialize(sb: string[]): void { - sb.push(this.value.toString()); + sb.push(this.value.toString(10)); } } @@ -1030,7 +1030,7 @@ export class BreakStatement extends Statement { serialize(sb: string[]): void { if (this.label) { sb.push("break "); - (this.label).serialize(name); + (this.label).serialize(sb); } else sb.push("break"); } diff --git a/src/diagnostics.ts b/src/diagnostics.ts index 009c7f8b..ccb70ee7 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -85,7 +85,7 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b sb.push(diagnosticCategoryToString(message.category)); if (useColors) sb.push(colorReset); sb.push(" AS"); - sb.push(message.code.toString()); + sb.push(message.code.toString(10)); sb.push(": "); sb.push(message.message); @@ -109,9 +109,9 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b sb.push(" in "); sb.push(range.source.path); sb.push("("); - sb.push(line.toString()); + sb.push(line.toString(10)); sb.push(","); - sb.push(column.toString()); + sb.push(column.toString(10)); sb.push(")"); } return sb.join(""); diff --git a/src/glue/binaryen-c.d.ts b/src/glue/binaryen-c.d.ts index 16cf9e26..33ac2ff8 100644 --- a/src/glue/binaryen-c.d.ts +++ b/src/glue/binaryen-c.d.ts @@ -60,10 +60,7 @@ declare type BinaryenModuleRef = usize; declare function _BinaryenModuleCreate(): BinaryenModuleRef; declare function _BinaryenModuleDispose(module: BinaryenModuleRef): void; -declare type CString = usize; -declare type CArray = usize; - -declare type BinaryenLiteral = CArray; +declare type BinaryenLiteral = usize; // LLVM C ABI with `out` being a buffer of 16 bytes receiving the BinaryenLiteral struct. // union value starts at offset 8 due to alignment (?) @@ -218,19 +215,19 @@ declare function _BinaryenAtomicRMWXchg(): BinaryenAtomicRMWOp; declare type BinaryenExpressionRef = usize; -declare function _BinaryenBlock(module: BinaryenModuleRef, name: CString, children: CArray, numChildren: BinaryenIndex, type: BinaryenType): BinaryenExpressionRef; +declare function _BinaryenBlock(module: BinaryenModuleRef, name: usize, children: usize, numChildren: BinaryenIndex, type: BinaryenType): BinaryenExpressionRef; declare function _BinaryenIf(module: BinaryenModuleRef, condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenLoop(module: BinaryenModuleRef, name: CString, body: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenBreak(module: BinaryenModuleRef, name: CString, condition: BinaryenExpressionRef, value: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenSwitch(module: BinaryenModuleRef, names: CArray, numNames: BinaryenIndex, defaultName: CString, condition: BinaryenExpressionRef, value: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenCall(module: BinaryenModuleRef, target: CString, operands: CArray, numOperands: BinaryenIndex, returnType: BinaryenType): BinaryenExpressionRef; -declare function _BinaryenCallImport(module: BinaryenModuleRef, target: CString, operands: CArray, numOperands: BinaryenIndex, returnType: BinaryenType): BinaryenExpressionRef; -declare function _BinaryenCallIndirect(module: BinaryenModuleRef, target: BinaryenExpressionRef, operands: CArray, numOperands: BinaryenIndex, type: CString): BinaryenExpressionRef; +declare function _BinaryenLoop(module: BinaryenModuleRef, name: usize, body: BinaryenExpressionRef): BinaryenExpressionRef; +declare function _BinaryenBreak(module: BinaryenModuleRef, name: usize, condition: BinaryenExpressionRef, value: BinaryenExpressionRef): BinaryenExpressionRef; +declare function _BinaryenSwitch(module: BinaryenModuleRef, names: usize, numNames: BinaryenIndex, defaultName: usize, condition: BinaryenExpressionRef, value: BinaryenExpressionRef): BinaryenExpressionRef; +declare function _BinaryenCall(module: BinaryenModuleRef, target: usize, operands: usize, numOperands: BinaryenIndex, returnType: BinaryenType): BinaryenExpressionRef; +declare function _BinaryenCallImport(module: BinaryenModuleRef, target: usize, operands: usize, numOperands: BinaryenIndex, returnType: BinaryenType): BinaryenExpressionRef; +declare function _BinaryenCallIndirect(module: BinaryenModuleRef, target: BinaryenExpressionRef, operands: usize, numOperands: BinaryenIndex, type: usize): BinaryenExpressionRef; declare function _BinaryenGetLocal(module: BinaryenModuleRef, index: BinaryenIndex, type: BinaryenType): BinaryenExpressionRef; declare function _BinaryenSetLocal(module: BinaryenModuleRef, index: BinaryenIndex, value: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenTeeLocal(module: BinaryenModuleRef, index: BinaryenIndex, value: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenGetGlobal(module: BinaryenModuleRef, name: CString, type: BinaryenType): BinaryenExpressionRef; -declare function _BinaryenSetGlobal(module: BinaryenModuleRef, name: CString, value: BinaryenExpressionRef): BinaryenExpressionRef; +declare function _BinaryenGetGlobal(module: BinaryenModuleRef, name: usize, type: BinaryenType): BinaryenExpressionRef; +declare function _BinaryenSetGlobal(module: BinaryenModuleRef, name: usize, value: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenLoad(module: BinaryenModuleRef, bytes: u32, signed: i8, offset: u32, align: u32, type: BinaryenType, ptr: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenStore(module: BinaryenModuleRef, bytes: u32, offset: u32, align: u32, ptr: BinaryenExpressionRef, value: BinaryenExpressionRef, type: BinaryenType): BinaryenExpressionRef; declare function _BinaryenConst(module: BinaryenModuleRef, value: BinaryenLiteral): BinaryenExpressionRef; @@ -239,7 +236,7 @@ declare function _BinaryenBinary(module: BinaryenModuleRef, op: BinaryenOp, left declare function _BinaryenSelect(module: BinaryenModuleRef, condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenDrop(module: BinaryenModuleRef, value: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenReturn(module: BinaryenModuleRef, value: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: CString | 0, operands: CArray, numOperands: BinaryenIndex): BinaryenExpressionRef; +declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: usize | 0, operands: usize, numOperands: BinaryenIndex): BinaryenExpressionRef; declare function _BinaryenNop(module: BinaryenModuleRef): BinaryenExpressionRef; declare function _BinaryenUnreachable(module: BinaryenModuleRef): BinaryenExpressionRef; declare function _BinaryenAtomicLoad(module: BinaryenModuleRef, bytes: BinaryenIndex, offset: BinaryenIndex, type: BinaryenType, ptr: BinaryenExpressionRef): BinaryenExpressionRef; @@ -253,7 +250,7 @@ declare function _BinaryenExpressionGetId(expr: BinaryenExpressionRef): Binaryen declare function _BinaryenExpressionGetType(expr: BinaryenExpressionRef): BinaryenType; declare function _BinaryenExpressionPrint(expr: BinaryenExpressionRef): void; -declare function _BinaryenBlockGetName(expr: BinaryenExpressionRef): CString; +declare function _BinaryenBlockGetName(expr: BinaryenExpressionRef): usize; declare function _BinaryenBlockGetNumChildren(expr: BinaryenExpressionRef): BinaryenIndex; declare function _BinaryenBlockGetChild(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef; @@ -261,24 +258,24 @@ declare function _BinaryenIfGetCondition(expr: BinaryenExpressionRef): BinaryenE declare function _BinaryenIfGetIfTrue(expr: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenIfGetIfFalse(expr: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenLoopGetName(expr: BinaryenExpressionRef): CString; +declare function _BinaryenLoopGetName(expr: BinaryenExpressionRef): usize; declare function _BinaryenLoopGetBody(expr: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenBreakGetName(expr: BinaryenExpressionRef): CString; +declare function _BinaryenBreakGetName(expr: BinaryenExpressionRef): usize; declare function _BinaryenBreakGetCondition(expr: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenBreakGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenSwitchGetNumNames(expr: BinaryenExpressionRef): BinaryenIndex; -declare function _BinaryenSwitchGetName(expr: BinaryenExpressionRef, index: BinaryenIndex): CString; -declare function _BinaryenSwitchGetDefaultName(expr: BinaryenExpressionRef): CString; +declare function _BinaryenSwitchGetName(expr: BinaryenExpressionRef, index: BinaryenIndex): usize; +declare function _BinaryenSwitchGetDefaultName(expr: BinaryenExpressionRef): usize; declare function _BinaryenSwitchGetCondition(expr: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenSwitchGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenCallGetTarget(expr: BinaryenExpressionRef): CString; +declare function _BinaryenCallGetTarget(expr: BinaryenExpressionRef): usize; declare function _BinaryenCallGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex; declare function _BinaryenCallGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef; -declare function _BinaryenCallImportGetTarget(expr: BinaryenExpressionRef): CString; +declare function _BinaryenCallImportGetTarget(expr: BinaryenExpressionRef): usize; declare function _BinaryenCallImportGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex; declare function _BinaryenCallImportGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef; @@ -292,13 +289,13 @@ declare function _BinaryenSetLocalIsTee(expr: BinaryenExpressionRef): bool; declare function _BinaryenSetLocalGetIndex(expr: BinaryenExpressionRef): BinaryenIndex; declare function _BinaryenSetLocalGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef; -declare function _BinaryenGetGlobalGetName(expr: BinaryenExpressionRef): CString; +declare function _BinaryenGetGlobalGetName(expr: BinaryenExpressionRef): usize; -declare function _BinaryenSetGlobalGetName(expr: BinaryenExpressionRef): CString; +declare function _BinaryenSetGlobalGetName(expr: BinaryenExpressionRef): usize; declare function _BinaryenSetGlobalGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef; declare function _BinaryenHostGetOp(expr: BinaryenExpressionRef): BinaryenOp; -declare function _BinaryenHostGetNameOperand(expr: BinaryenExpressionRef): CString; +declare function _BinaryenHostGetNameOperand(expr: BinaryenExpressionRef): usize; declare function _BinaryenHostGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex; declare function _BinaryenHostGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef; @@ -359,21 +356,21 @@ declare function _BinaryenAtomicWakeGetWakeCount(expr: BinaryenExpressionRef): B declare type BinaryenFunctionTypeRef = usize; -declare function _BinaryenAddFunctionType(module: BinaryenModuleRef, name: CString, result: BinaryenType, paramTypes: CArray, numParams: BinaryenIndex): BinaryenFunctionTypeRef; -declare function _BinaryenGetFunctionTypeBySignature(module: BinaryenModuleRef, result: BinaryenType, paramTypes: CArray, numParams: BinaryenIndex): BinaryenFunctionTypeRef; +declare function _BinaryenAddFunctionType(module: BinaryenModuleRef, name: usize, result: BinaryenType, paramTypes: usize, numParams: BinaryenIndex): BinaryenFunctionTypeRef; +declare function _BinaryenGetFunctionTypeBySignature(module: BinaryenModuleRef, result: BinaryenType, paramTypes: usize, numParams: BinaryenIndex): BinaryenFunctionTypeRef; -declare function _BinaryenFunctionTypeGetName(ftype: BinaryenFunctionTypeRef): CString; +declare function _BinaryenFunctionTypeGetName(ftype: BinaryenFunctionTypeRef): usize; declare function _BinaryenFunctionTypeGetNumParams(ftype: BinaryenFunctionTypeRef): BinaryenIndex; declare function _BinaryenFunctionTypeGetParam(ftype: BinaryenFunctionTypeRef, index: BinaryenIndex): BinaryenType; declare function _BinaryenFunctionTypeGetResult(ftype: BinaryenFunctionTypeRef): BinaryenType; declare type BinaryenFunctionRef = usize; -declare function _BinaryenAddFunction(module: BinaryenModuleRef, name: CString, type: BinaryenFunctionTypeRef, varTypes: CArray, numVarTypes: BinaryenIndex, body: BinaryenExpressionRef): BinaryenFunctionRef; -declare function _BinaryenGetFunction(module: BinaryenModuleRef, name: CString): BinaryenFunctionRef; -declare function _BinaryenRemoveFunction(module: BinaryenModuleRef, name: CString): void; +declare function _BinaryenAddFunction(module: BinaryenModuleRef, name: usize, type: BinaryenFunctionTypeRef, varTypes: usize, numVarTypes: BinaryenIndex, body: BinaryenExpressionRef): BinaryenFunctionRef; +declare function _BinaryenGetFunction(module: BinaryenModuleRef, name: usize): BinaryenFunctionRef; +declare function _BinaryenRemoveFunction(module: BinaryenModuleRef, name: usize): void; -declare function _BinaryenFunctionGetName(func: BinaryenFunctionRef): CString; +declare function _BinaryenFunctionGetName(func: BinaryenFunctionRef): usize; declare function _BinaryenFunctionGetType(func: BinaryenFunctionRef): BinaryenFunctionTypeRef; declare function _BinaryenFunctionGetNumParams(func: BinaryenFunctionRef): BinaryenIndex; declare function _BinaryenFunctionGetParam(func: BinaryenFunctionRef, index: BinaryenIndex): BinaryenType; @@ -382,43 +379,43 @@ declare function _BinaryenFunctionGetNumVars(func: BinaryenFunctionRef): Binarye declare function _BinaryenFunctionGetVar(func: BinaryenFunctionRef, index: BinaryenIndex): BinaryenType; declare function _BinaryenFunctionGetBody(func: BinaryenFunctionRef): BinaryenExpressionRef; declare function _BinaryenFunctionOptimize(func: BinaryenFunctionRef, module: BinaryenModuleRef): void; -declare function _BinaryenFunctionRunPasses(func: BinaryenFunctionRef, module: BinaryenModuleRef, passes: CArray, numPasses: BinaryenIndex): void; +declare function _BinaryenFunctionRunPasses(func: BinaryenFunctionRef, module: BinaryenModuleRef, passes: usize, numPasses: BinaryenIndex): void; declare type BinaryenImportRef = usize; -declare function _BinaryenAddFunctionImport(module: BinaryenModuleRef, internalName: CString, externalModuleName: CString, externalBaseName: CString, functionType: BinaryenFunctionTypeRef): BinaryenImportRef; -declare function _BinaryenAddTableImport(module: BinaryenModuleRef, internalName: CString, externalModuleName: CString, externalBaseName: CString): BinaryenImportRef; -declare function _BinaryenAddMemoryImport(module: BinaryenModuleRef, internalName: CString, externalModuleName: CString, externalBaseName: CString): BinaryenImportRef; -declare function _BinaryenAddGlobalImport(module: BinaryenModuleRef, internalName: CString, externalModuleName: CString, externalBaseName: CString, globalType: BinaryenType): BinaryenImportRef; -declare function _BinaryenRemoveImport(module: BinaryenModuleRef, internalName: CString): void; +declare function _BinaryenAddFunctionImport(module: BinaryenModuleRef, internalName: usize, externalModuleName: usize, externalBaseName: usize, functionType: BinaryenFunctionTypeRef): BinaryenImportRef; +declare function _BinaryenAddTableImport(module: BinaryenModuleRef, internalName: usize, externalModuleName: usize, externalBaseName: usize): BinaryenImportRef; +declare function _BinaryenAddMemoryImport(module: BinaryenModuleRef, internalName: usize, externalModuleName: usize, externalBaseName: usize): BinaryenImportRef; +declare function _BinaryenAddGlobalImport(module: BinaryenModuleRef, internalName: usize, externalModuleName: usize, externalBaseName: usize, globalType: BinaryenType): BinaryenImportRef; +declare function _BinaryenRemoveImport(module: BinaryenModuleRef, internalName: usize): void; declare type BinaryenExportRef = usize; -declare function _BinaryenAddFunctionExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef; -declare function _BinaryenAddTableExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef; -declare function _BinaryenAddMemoryExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef; -declare function _BinaryenAddGlobalExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef; -declare function _BinaryenRemoveExport(module: BinaryenModuleRef, externalName: CString): void; +declare function _BinaryenAddFunctionExport(module: BinaryenModuleRef, internalName: usize, externalName: usize): BinaryenExportRef; +declare function _BinaryenAddTableExport(module: BinaryenModuleRef, internalName: usize, externalName: usize): BinaryenExportRef; +declare function _BinaryenAddMemoryExport(module: BinaryenModuleRef, internalName: usize, externalName: usize): BinaryenExportRef; +declare function _BinaryenAddGlobalExport(module: BinaryenModuleRef, internalName: usize, externalName: usize): BinaryenExportRef; +declare function _BinaryenRemoveExport(module: BinaryenModuleRef, externalName: usize): void; declare type BinaryenGlobalRef = usize; -declare function _BinaryenAddGlobal(module: BinaryenModuleRef, name: CString, type: BinaryenType, mutable: i8, init: BinaryenExpressionRef): BinaryenGlobalRef; +declare function _BinaryenAddGlobal(module: BinaryenModuleRef, name: usize, type: BinaryenType, mutable: i8, init: BinaryenExpressionRef): BinaryenGlobalRef; -declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, funcs: CArray, numFuncs: BinaryenIndex): void; +declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, funcs: usize, numFuncs: BinaryenIndex): void; -declare function _BinaryenSetMemory(module: BinaryenModuleRef, initial: BinaryenIndex, maximum: BinaryenIndex, exportName: CString, segments: CArray>, segmentOffsets: CArray, segmentSizes: CArray, numSegments: BinaryenIndex): void; +declare function _BinaryenSetMemory(module: BinaryenModuleRef, initial: BinaryenIndex, maximum: BinaryenIndex, exportName: usize, segments: usize, segmentOffsets: usize, segmentSizes: usize, numSegments: BinaryenIndex): void; declare function _BinaryenSetStart(module: BinaryenModuleRef, start: BinaryenFunctionRef): void; -declare function _BinaryenModuleParse(text: CString): BinaryenModuleRef; +declare function _BinaryenModuleParse(text: usize): BinaryenModuleRef; declare function _BinaryenModulePrint(module: BinaryenModuleRef): void; declare function _BinaryenModulePrintAsmjs(module: BinaryenModuleRef): void; declare function _BinaryenModuleValidate(module: BinaryenModuleRef): i32; declare function _BinaryenModuleOptimize(module: BinaryenModuleRef): void; -declare function _BinaryenModuleRunPasses(module: BinaryenModuleRef, passes: CArray, numPasses: BinaryenIndex): void; +declare function _BinaryenModuleRunPasses(module: BinaryenModuleRef, passes: usize, numPasses: BinaryenIndex): void; declare function _BinaryenModuleAutoDrop(module: BinaryenModuleRef): void; -declare function _BinaryenModuleWrite(module: BinaryenModuleRef, output: CString, outputSize: usize): usize; -declare function _BinaryenModuleRead(input: CString, inputSize: usize): BinaryenModuleRef; +declare function _BinaryenModuleWrite(module: BinaryenModuleRef, output: usize, outputSize: usize): usize; +declare function _BinaryenModuleRead(input: usize, inputSize: usize): BinaryenModuleRef; declare function _BinaryenModuleInterpret(module: BinaryenModuleRef): void; declare type RelooperRef = usize; @@ -428,7 +425,7 @@ declare function _RelooperCreate(): RelooperRef; declare function _RelooperAddBlock(relooper: RelooperRef, code: BinaryenExpressionRef): RelooperBlockRef; declare function _RelooperAddBranch(from: RelooperBlockRef, to: RelooperBlockRef, condition: BinaryenExpressionRef, code: BinaryenExpressionRef): void; declare function _RelooperAddBlockWithSwitch(relooper: RelooperRef, code: BinaryenExpressionRef, condition: BinaryenExpressionRef): RelooperBlockRef; -declare function _RelooperAddBranchForSwitch(from: RelooperBlockRef, to: RelooperBlockRef, indexes: CArray, numIndexes: BinaryenIndex, code: BinaryenExpressionRef): void; +declare function _RelooperAddBranchForSwitch(from: RelooperBlockRef, to: RelooperBlockRef, indexes: usize, numIndexes: BinaryenIndex, code: BinaryenExpressionRef): void; declare function _RelooperRenderAndDispose(relooper: RelooperRef, entry: RelooperBlockRef, labelHelper: BinaryenIndex, module: BinaryenModuleRef): BinaryenExpressionRef; declare function _BinaryenSetAPITracing(on: i32): void; diff --git a/src/glue/js.d.ts b/src/glue/js.d.ts index 6f07721b..8e3790eb 100644 --- a/src/glue/js.d.ts +++ b/src/glue/js.d.ts @@ -1,6 +1,3 @@ -/// -/// - // Raw memory accesses to Binaryen memory declare function store(ptr: usize, val: T): void; declare function load(ptr: usize): T; diff --git a/src/glue/js.js b/src/glue/js.js index 01f77644..b7d415a2 100644 --- a/src/glue/js.js +++ b/src/glue/js.js @@ -1,7 +1,7 @@ -require("../../portable-assembly"); +require("../../portable-assembly"); // not inherited from tsconfig by ts-node otherwise :( +// Copy Binaryen exports to global scope var globalScope = typeof window !== "undefined" && window || typeof global !== "undefined" && global || self; - var binaryen; try { binaryen = require("binaryen"); @@ -9,29 +9,36 @@ try { binaryen = globalScope["Binaryen"]; } for (var key in binaryen) - if (/^_(?:Binaryen|Relooper|malloc$|free$)/.test(key)) + if (/^_(?:Binaryen|Relooper)/.test(key)) globalScope[key] = binaryen[key]; +// Use Binaryen's heap +Object.defineProperties(globalScope['Heap'] = { + allocate: binaryen._malloc, + dispose: binaryen._free +}, { + 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) { binaryen.HEAPU8[ptr] = val; }; - globalScope["load"] = function load_u8(ptr) { return binaryen.HEAPU8[ptr]; }; +// Implement module stubs var Module = require("../module").Module; - Module.prototype.toBinary = function toBinary(bufferSize) { - if (!bufferSize) bufferSize = 1024 * 1024; + if (!bufferSize) bufferSize = 1024 * 1024; // FIXME: see binaryen.js-post.js in Binaryen var ptr = _malloc(bufferSize); var len = this.write(ptr, bufferSize); var ret = new Uint8Array(len); ret.set(binaryen.HEAPU8.subarray(ptr, ptr + len)); _free(ptr); return ret; -} - +}; Module.prototype.toText = function toText() { var previousPrint = binaryen.print; var ret = ""; @@ -39,8 +46,7 @@ Module.prototype.toText = function toText() { this.print(); binaryen.print = previousPrint; return ret; -} - +}; Module.prototype.toAsmjs = function toAsmjs() { var previousPrint = binaryen.print; var ret = ""; @@ -48,4 +54,4 @@ Module.prototype.toAsmjs = function toAsmjs() { this.printAsmjs(); binaryen.print = previousPrint; return ret; -} +}; diff --git a/src/module.ts b/src/module.ts index 39e3d295..d06f1efa 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,14 +1,14 @@ import { I64, U64 } from "./util"; import { Target } from "./compiler"; -export type ModuleRef = BinaryenModuleRef; -export type FunctionTypeRef = BinaryenFunctionTypeRef; -export type FunctionRef = BinaryenFunctionRef; -export type ExpressionRef = BinaryenExpressionRef; -export type GlobalRef = BinaryenGlobalRef; -export type ImportRef = BinaryenImportRef; -export type ExportRef = BinaryenExportRef; -export type Index = BinaryenIndex; +export type ModuleRef = usize; +export type FunctionTypeRef = usize; +export type FunctionRef = usize; +export type ExpressionRef = usize; +export type GlobalRef = usize; +export type ImportRef = usize; +export type ExportRef = usize; +export type Index = u32; export enum NativeType { None = _BinaryenNone(), @@ -219,28 +219,28 @@ export class Module { static create(): Module { const module: Module = new Module(); module.ref = _BinaryenModuleCreate(); - module.lit = _malloc(16); + module.lit = changetype(Heap.allocate(16)); module.noEmit = false; return module; } static createFrom(buffer: Uint8Array): Module { - const cArr: CArray = allocU8Array(buffer); + const cArr: usize = allocU8Array(buffer); try { const module: Module = new Module(); module.ref = _BinaryenModuleRead(cArr, buffer.length); - module.lit = _malloc(16); + module.lit = changetype(Heap.allocate(16)); module.noEmit = false; return module; } finally { - _free(cArr); + Heap.dispose(changetype(cArr)); } } static createStub(): Module { const module: Module = new Module(); module.ref = 0; - module.lit = 0; + module.lit = changetype(0); module.noEmit = true; return module; } @@ -251,23 +251,23 @@ export class Module { addFunctionType(name: string, result: NativeType, paramTypes: NativeType[]): FunctionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(name); - const cArr: CArray = allocI32Array(paramTypes); + const cStr: usize = allocString(name); + const cArr: usize = allocI32Array(paramTypes); try { return _BinaryenAddFunctionType(this.ref, cStr, result, cArr, paramTypes.length); } finally { - _free(cArr); - _free(cStr); + Heap.dispose(cArr); + Heap.dispose(cStr); } } getFunctionTypeBySignature(result: NativeType, paramTypes: NativeType[]): FunctionTypeRef { if (this.noEmit) return 0; - const cArr: CArray = allocI32Array(paramTypes); + const cArr: usize = allocI32Array(paramTypes); try { return _BinaryenGetFunctionTypeBySignature(this.ref, result, cArr, paramTypes.length); } finally { - _free(cArr); + Heap.dispose(cArr); } } @@ -309,13 +309,13 @@ export class Module { createHost(op: HostOp, name: string | null = null, operands: ExpressionRef[] | null = null): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(name); - const cArr: CArray = allocI32Array(operands); + const cStr: usize = allocString(name); + const cArr: usize = allocI32Array(operands); try { return _BinaryenHost(this.ref, op, cStr, cArr, operands ? (operands).length : 0); } finally { - _free(cArr); - _free(cStr); + Heap.dispose(cArr); + Heap.dispose(cStr); } } @@ -331,11 +331,11 @@ export class Module { createGetGlobal(name: string, type: NativeType): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(name); + const cStr: usize = allocString(name); try { return _BinaryenGetGlobal(this.ref, cStr, type); } finally { - _free(cStr); + Heap.dispose(cStr); } } @@ -388,33 +388,33 @@ export class Module { createSetGlobal(name: string, value: ExpressionRef): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(name); + const cStr: usize = allocString(name); try { return _BinaryenSetGlobal(this.ref, cStr, value); } finally { - _free(cStr); + Heap.dispose(cStr); } } createBlock(label: string | null, children: ExpressionRef[], type: NativeType = NativeType.Undefined): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(label); - const cArr: CArray = allocI32Array(children); + const cStr: usize = allocString(label); + const cArr: usize = allocI32Array(children); try { return _BinaryenBlock(this.ref, cStr, cArr, children.length, type); } finally { - _free(cArr); - _free(cStr); + Heap.dispose(cArr); + Heap.dispose(cStr); } } createBreak(label: string | null, condition: ExpressionRef = 0, value: ExpressionRef = 0): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(label); + const cStr: usize = allocString(label); try { return _BinaryenBreak(this.ref, cStr, condition, value); } finally { - _free(cStr); + Heap.dispose(cStr); } } @@ -425,11 +425,11 @@ export class Module { createLoop(label: string | null, body: ExpressionRef): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(label); + const cStr: usize = allocString(label); try { return _BinaryenLoop(this.ref, cStr, body); } finally { - _free(cStr); + Heap.dispose(cStr); } } @@ -455,41 +455,41 @@ export class Module { createSwitch(names: string[], defaultName: string | null, condition: ExpressionRef, value: ExpressionRef = 0): ExpressionRef { if (this.noEmit) return 0; - const strs: CString[] = new Array(names.length); + const strs: usize[] = new Array(names.length); let i: i32, k: i32 = names.length; for (i = 0; i < k; ++i) strs[i] = allocString(names[i]); - const cArr: CArray = allocI32Array(strs); - const cStr: CString = allocString(defaultName); + const cArr: usize = allocI32Array(strs); + const cStr: usize = allocString(defaultName); try { return _BinaryenSwitch(this.ref, cArr, k, cStr, condition, value); } finally { - _free(cStr); - _free(cArr); - for (i = k - 1; i >= 0; --i) _free(strs[i]); + Heap.dispose(cStr); + Heap.dispose(cArr); + for (i = k - 1; i >= 0; --i) Heap.dispose(strs[i]); } } createCall(target: string, operands: ExpressionRef[], returnType: NativeType): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(target); - const cArr: CArray = allocI32Array(operands); + const cStr: usize = allocString(target); + const cArr: usize = allocI32Array(operands); try { return _BinaryenCall(this.ref, cStr, cArr, operands.length, returnType); } finally { - _free(cArr); - _free(cStr); + Heap.dispose(cArr); + Heap.dispose(cStr); } } createCallImport(target: string, operands: ExpressionRef[], returnType: NativeType): ExpressionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(target); - const cArr: CArray = allocI32Array(operands); + const cStr: usize = allocString(target); + const cArr: usize = allocI32Array(operands); try { return _BinaryenCallImport(this.ref, cStr, cArr, operands.length, returnType); } finally { - _free(cArr); - _free(cStr); + Heap.dispose(cArr); + Heap.dispose(cStr); } } @@ -502,80 +502,80 @@ export class Module { addGlobal(name: string, type: NativeType, mutable: bool, initializer: ExpressionRef): GlobalRef { if (this.noEmit) return 0; - const cStr: CString = allocString(name); + const cStr: usize = allocString(name); try { return _BinaryenAddGlobal(this.ref, cStr, type, mutable ? 1 : 0, initializer); } finally { - _free(cStr); + Heap.dispose(cStr); } } addFunction(name: string, type: FunctionTypeRef, varTypes: NativeType[], body: ExpressionRef): FunctionRef { if (this.noEmit) return 0; - const cStr: CString = allocString(name); - const cArr: CArray = allocI32Array(varTypes); + const cStr: usize = allocString(name); + const cArr: usize = allocI32Array(varTypes); try { return _BinaryenAddFunction(this.ref, cStr, type, cArr, varTypes.length, body); } finally { - _free(cArr); - _free(cStr); + Heap.dispose(cArr); + Heap.dispose(cStr); } } removeFunction(name: string): void { - const cStr: CString = allocString(name); + const cStr: usize = allocString(name); try { _BinaryenRemoveFunction(this.ref, cStr); } finally { - _free(cStr); + Heap.dispose(cStr); } } addFunctionExport(internalName: string, externalName: string): ExportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalName); try { return _BinaryenAddFunctionExport(this.ref, cStr1, cStr2); } finally { - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } addTableExport(internalName: string, externalName: string): ExportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalName); try { return _BinaryenAddTableExport(this.ref, cStr1, cStr2); } finally { - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } addMemoryExport(internalName: string, externalName: string): ExportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalName); try { return _BinaryenAddMemoryExport(this.ref, cStr1, cStr2); } finally { - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } addGlobalExport(internalName: string, externalName: string): ExportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalName); try { return _BinaryenAddGlobalExport(this.ref, cStr1, cStr2); } finally { - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } @@ -585,81 +585,81 @@ export class Module { try { _BinaryenRemoveExport(this.ref, cStr); } finally { - _free(cStr); + Heap.dispose(cStr); } } addFunctionImport(internalName: string, externalModuleName: string, externalBaseName: string, functionType: FunctionTypeRef): ImportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalModuleName); - const cStr3: CString = allocString(externalBaseName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalModuleName); + const cStr3: usize = allocString(externalBaseName); try { return _BinaryenAddFunctionImport(this.ref, cStr1, cStr2, cStr3, functionType); } finally { - _free(cStr3); - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr3); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } addTableImport(internalName: string, externalModuleName: string, externalBaseName: string): ImportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalModuleName); - const cStr3: CString = allocString(externalBaseName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalModuleName); + const cStr3: usize = allocString(externalBaseName); try { return _BinaryenAddTableImport(this.ref, cStr1, cStr2, cStr3); } finally { - _free(cStr3); - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr3); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } addMemoryImport(internalName: string, externalModuleName: string, externalBaseName: string): ImportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalModuleName); - const cStr3: CString = allocString(externalBaseName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalModuleName); + const cStr3: usize = allocString(externalBaseName); try { return _BinaryenAddMemoryImport(this.ref, cStr1, cStr2, cStr3); } finally { - _free(cStr3); - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr3); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } addGlobalImport(internalName: string, externalModuleName: string, externalBaseName: string, globalType: NativeType): ImportRef { if (this.noEmit) return 0; - const cStr1: CString = allocString(internalName); - const cStr2: CString = allocString(externalModuleName); - const cStr3: CString = allocString(externalBaseName); + const cStr1: usize = allocString(internalName); + const cStr2: usize = allocString(externalModuleName); + const cStr3: usize = allocString(externalBaseName); try { return _BinaryenAddGlobalImport(this.ref, cStr1, cStr2, cStr3, globalType); } finally { - _free(cStr3); - _free(cStr2); - _free(cStr1); + Heap.dispose(cStr3); + Heap.dispose(cStr2); + Heap.dispose(cStr1); } } removeImport(internalName: string): void { if (this.noEmit) return; - const cStr: CString = allocString(internalName); + const cStr: usize = allocString(internalName); try { _BinaryenRemoveImport(this.ref, cStr); } finally { - _free(cStr); + Heap.dispose(cStr); } } setMemory(initial: Index, maximum: Index, segments: MemorySegment[], target: Target, exportName: string | null = null): void { if (this.noEmit) return; - const cStr: CString = allocString(exportName); + const cStr: usize = allocString(exportName); let i: i32, k: i32 = segments.length; - const segs: CArray[] = new Array(k); + const segs: usize[] = new Array(k); const offs: ExpressionRef[] = new Array(k); const sizs: Index[] = new Array(k); for (i = 0; i < k; ++i) { @@ -671,27 +671,27 @@ export class Module { : this.createI32(offset.toI32()); sizs[i] = buffer.length; } - const cArr1: CArray = allocI32Array(segs); - const cArr2: CArray = allocI32Array(offs); - const cArr3: CArray = allocI32Array(sizs); + const cArr1: usize = allocI32Array(segs); + const cArr2: usize = allocI32Array(offs); + const cArr3: usize = allocI32Array(sizs); try { _BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, k); } finally { - _free(cArr3); - _free(cArr2); - _free(cArr1); - for (i = k - 1; i >= 0; --i) _free(segs[i]); - _free(cStr); + Heap.dispose(cArr3); + Heap.dispose(cArr2); + Heap.dispose(cArr1); + for (i = k - 1; i >= 0; --i) Heap.dispose(segs[i]); + Heap.dispose(cStr); } } - setFunctionTable(funcs: BinaryenFunctionRef[]): void { + setFunctionTable(funcs: FunctionRef[]): void { if (this.noEmit) return; - const cArr: CArray = allocI32Array(funcs); + const cArr: usize = allocI32Array(funcs); try { _BinaryenSetFunctionTable(this.ref, cArr, funcs.length); } finally { - _free(cArr); + Heap.dispose(cArr); } } @@ -712,17 +712,17 @@ export class Module { runPasses(passes: string[], func: FunctionRef = 0): void { let i: i32, k: i32 = passes.length; - const names: CString[] = new Array(k); + const names: usize[] = new Array(k); for (i = 0; i < k; ++i) names[i] = allocString(passes[i]); - const cArr: CArray = allocI32Array(names); + const cArr: usize = allocI32Array(names); try { if (func) _BinaryenFunctionRunPasses(func, this.ref, cArr, k); else _BinaryenModuleRunPasses(this.ref, cArr, k); } finally { - _free(cArr); - for (; i >= 0; --i) _free(names[i]); + Heap.dispose(cArr); + for (; i >= 0; --i) Heap.dispose(names[i]); } } @@ -760,7 +760,7 @@ export class Module { dispose(): void { if (!this.ref) return; // sic _BinaryenModuleDispose(this.ref); - _free(this.lit); + Heap.dispose(changetype(this.lit)); } createRelooper(): Relooper { @@ -900,11 +900,11 @@ export class Relooper { addBranchForSwitch(from: RelooperBlockRef, to: RelooperBlockRef, indexes: i32[], code: ExpressionRef = 0): void { if (this.noEmit) return; - const cArr: CArray = allocI32Array(indexes); + const cArr: usize = allocI32Array(indexes); try { _RelooperAddBranchForSwitch(from, to, cArr, indexes.length, code); } finally { - _free(cArr); + Heap.dispose(cArr); } } @@ -921,18 +921,18 @@ export function setAPITracing(on: bool): void { // helpers // can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js -function allocU8Array(u8s: Uint8Array | null): CArray { +function allocU8Array(u8s: Uint8Array | null): usize { if (!u8s) return 0; - const ptr: usize = _malloc((u8s).length); + const ptr: usize = Heap.allocate((u8s).length); let idx: usize = ptr; for (let i: i32 = 0, k: i32 = (u8s).length; i < k; ++i) store(idx++, (u8s)[i]) return ptr; } -function allocI32Array(i32s: i32[] | null): CArray { +function allocI32Array(i32s: i32[] | null): usize { if (!i32s) return 0; - const ptr: usize = _malloc((i32s).length << 2); + const ptr: usize = Heap.allocate((i32s).length << 2); let idx: usize = ptr; for (let i: i32 = 0, k: i32 = (i32s).length; i < k; ++i) { let val: i32 = (i32s)[i]; @@ -967,9 +967,9 @@ function stringLengthUTF8(str: string): usize { return len; } -function allocString(str: string | null): CString { +function allocString(str: string | null): usize { if (!str) return 0; - const ptr: usize = _malloc(stringLengthUTF8((str)) + 1); + const ptr: usize = Heap.allocate(stringLengthUTF8((str)) + 1); let idx: usize = ptr; for (let i: i32 = 0, k: i32 = (str).length; i < k; ++i) { let u: i32 = (str).charCodeAt(i); diff --git a/src/parser.ts b/src/parser.ts index b28256e2..020791f9 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -81,7 +81,7 @@ export class Parser extends DiagnosticEmitter { const normalizedPath: string = normalizePath(path); for (let i: i32 = 0, k: i32 = this.program.sources.length; i < k; ++i) if (this.program.sources[i].normalizedPath == normalizedPath) - throw Error("duplicate source"); + throw new Error("duplicate source"); this.seenlog.add(normalizedPath); const source: Source = new Source(path, text, isEntry); diff --git a/src/program.ts b/src/program.ts index e9d618e4..b8870b0c 100644 --- a/src/program.ts +++ b/src/program.ts @@ -83,6 +83,7 @@ export class Program extends DiagnosticEmitter { /** Initializes the program and its elements prior to compilation. */ initialize(target: Target = Target.WASM32): void { this.target = target; + this.types = new Map([ ["i8", Type.i8], ["i16", Type.i16], diff --git a/src/tsconfig.json b/src/tsconfig.json index 01693dcb..8014651d 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -1,47 +1,10 @@ { + "extends": "../portable-assembly.json", "compilerOptions": { - "target": "es5", - "module": "commonjs", - "lib": [ - "dom", - "es6" - ], - "types": [ - "node" - ], - "downlevelIteration": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "alwaysStrict": true, - "noImplicitReturns": true, - "noImplicitAny": true, - "noImplicitThis": true, - "preserveConstEnums": true, "outDir": "../out", "sourceMap": true }, - "files": [ - "ast.ts", - "builtins.ts", - "compiler.ts", - "diagnosticMessages.generated.ts", - "diagnostics.ts", - "evaluator.ts", - "glue/js.d.ts", - "index.ts", - "module.ts", - "parser.ts", - "program.ts", - "tokenizer.ts", - "types.ts", - "util.ts", - "util/charcode.ts", - "util/i64.ts", - "util/path.ts" - ], - "assembly": { - "exclude": [ - "glue/js.d.ts" - ] - } + "include": [ + "./**/*.ts" + ] } diff --git a/src/util/i64.ts b/src/util/i64.ts index ccd51db5..e74e4ddc 100644 --- a/src/util/i64.ts +++ b/src/util/i64.ts @@ -421,7 +421,7 @@ export class I64 { lo = "0" + lo; return (negative ? "-0x" : "0x") + (i64_hi as u32 >>> 0).toString(16) + lo; } - return negative ? "-" + i64_lo.toString() : i64_lo.toString(); + return negative ? "-" + i64_lo.toString(10) : i64_lo.toString(10); } } diff --git a/std/impl/heap.ts b/std/assembly/heap.ts similarity index 99% rename from std/impl/heap.ts rename to std/assembly/heap.ts index aa351d8b..0771f92c 100644 --- a/std/impl/heap.ts +++ b/std/assembly/heap.ts @@ -1,5 +1,3 @@ -/// - const ALIGN_LOG2: usize = 3; const ALIGN_SIZE: usize = 1 << ALIGN_LOG2; const ALIGN_MASK: usize = ALIGN_SIZE - 1; diff --git a/std/assembly/tsconfig.json b/std/assembly/tsconfig.json new file mode 100644 index 00000000..11e71a59 --- /dev/null +++ b/std/assembly/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../assembly.json", + "compilerOptions": { + "diagnostics": true + }, + "include": [ + "./**/*.ts" + ] +} diff --git a/std/carray.d.ts b/std/carray.d.ts deleted file mode 100644 index 3cae38e9..00000000 --- a/std/carray.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/// - -/** A C-compatible array class. */ -declare class CArray { - [key: number]: T; - - /** Constructs a new C-Array of the specified capacity. */ - constructor(capacity: usize); - - /** Disposes this instance and the memory associated with it. */ - dispose(): void; -} diff --git a/std/cstring.d.ts b/std/cstring.d.ts deleted file mode 100644 index c2bcff1f..00000000 --- a/std/cstring.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/// - -/** A C-compatible string class. */ -declare class CString { - readonly [key: number]: u8; - - /** Constructs a new C-String from a standard string. */ - constructor(string: string); - - /** Disposes this instance and the memory associated with it. */ - dispose(): void; -} diff --git a/std/impl/carray.ts b/std/impl/carray.ts deleted file mode 100644 index 45ee276b..00000000 --- a/std/impl/carray.ts +++ /dev/null @@ -1,25 +0,0 @@ -/// - -@global() -@struct() -class CArray { - - constructor(capacity: usize) { - return changetype(Heap.allocate(capacity * sizeof())); - } - - @inline() - "[]"(index: usize): T { - return load(changetype(this) + index * sizeof()); - } - - @inline() - "[]="(index: usize, value: T): T { - store(changetype(this) + index * sizeof(), value); - return value; - } - - dispose(): void { - Heap.dispose(changetype(this)); - } -} diff --git a/std/impl/cstring.ts b/std/impl/cstring.ts deleted file mode 100644 index ec62961a..00000000 --- a/std/impl/cstring.ts +++ /dev/null @@ -1,58 +0,0 @@ -/// - -@global() -@struct() -class CString { - - constructor(string: string) { - const ptr: usize = Heap.allocate(string.length * 2 + 1); - let idx: usize = ptr; - for (let i: usize = 0, k: usize = (str).length; i < k; ++i) { - let u: i32 = string.charCodeAt(i); - if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) - u = 0x10000 + ((u & 0x3FF) << 10) | (string.charCodeAt(++i) & 0x3FF); - if (u <= 0x7F) - store(idx++, u as u8); - else if (u <= 0x7FF) { - // TODO: maybe combine multiple stores into the next larger one - store(idx++, (0xC0 | (u >>> 6) ) as u8); - store(idx++, (0x80 | ( u & 63)) as u8); - } else if (u <= 0xFFFF) { - store(idx++, (0xE0 | (u >>> 12) ) as u8); - store(idx++, (0x80 | ((u >>> 6) & 63)) as u8); - store(idx++, (0x80 | ( u & 63)) as u8); - } else if (u <= 0x1FFFFF) { - store(idx++, (0xF0 | (u >>> 18) ) as u8); - store(idx++, (0x80 | ((u >>> 12) & 63)) as u8); - store(idx++, (0x80 | ((u >>> 6) & 63)) as u8); - store(idx++, (0x80 | ( u & 63)) as u8); - } else if (u <= 0x3FFFFFF) { - store(idx++, (0xF8 | (u >>> 24) ) as u8); - store(idx++, (0x80 | ((u >>> 18) & 63)) as u8); - store(idx++, (0x80 | ((u >>> 12) & 63)) as u8); - store(idx++, (0x80 | ((u >>> 6) & 63)) as u8); - store(idx++, (0x80 | ( u & 63)) as u8); - } else { - store(idx++, (0xFC | (u >>> 30) ) as u8); - store(idx++, (0x80 | ((u >>> 24) & 63)) as u8); - store(idx++, (0x80 | ((u >>> 18) & 63)) as u8); - store(idx++, (0x80 | ((u >>> 12) & 63)) as u8); - store(idx++, (0x80 | ((u >>> 6) & 63)) as u8); - store(idx++, (0x80 | ( u & 63)) as u8); - } - } - store(idx, 0); - return changetype(ptr); - } - - @inline() - "[]"(index: usize): u8 { - return load(changetype(this) + index /* * sizeof() */); - } - - // read-only - - dispose(): void { - Heap.dispose(changetype(this)); - } -} diff --git a/std/impl/tsconfig.json b/std/impl/tsconfig.json deleted file mode 100644 index b8e74559..00000000 --- a/std/impl/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "noLib": true, - "experimentalDecorators": true - }, - "files": [ - "carray.ts", - "cstring.ts", - "heap.ts" - ] -} \ No newline at end of file diff --git a/std/heap.ts b/std/portable/heap.d.ts similarity index 76% rename from std/heap.ts rename to std/portable/heap.d.ts index 7309739a..f402cca8 100644 --- a/std/heap.ts +++ b/std/portable/heap.d.ts @@ -1,5 +1,3 @@ -/// - /** A static class representing the heap. */ declare class Heap { @@ -10,11 +8,11 @@ declare class Heap { static dispose(ptr: usize): void; /** Gets the amount of used heap space, in bytes. */ - static get used(): usize; + static readonly used: usize; /** Gets the amount of free heap space, in bytes. */ - static get free(): usize; + static readonly free: usize; /** Gets the size of the heap, in bytes. */ - static get size(): usize; + static readonly size: usize; } diff --git a/std/portable/heap.js b/std/portable/heap.js new file mode 100644 index 00000000..7d1597ae --- /dev/null +++ b/std/portable/heap.js @@ -0,0 +1,9 @@ +var globalScope = typeof window !== "undefined" && window || typeof global !== "undefined" && global || self; + +globalScope["Heap"] = { + allocate: function() { throw new Error("not implemented"); }, + dispose: function() { throw new Error("not implemented"); }, + used: 0, + free: 0, + size: 0 +}; diff --git a/std/portable/tsconfig.json b/std/portable/tsconfig.json new file mode 100644 index 00000000..97751bee --- /dev/null +++ b/std/portable/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../portable-assembly.json", + "compilerOptions": { + "diagnostics": true + }, + "include": [ + "./**/*.ts" + ] +} diff --git a/std/tsconfig.json b/std/tsconfig.json deleted file mode 100644 index 6e2597ab..00000000 --- a/std/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "noLib": true, - "experimentalDecorators": true - }, - "files": [ - "carray.d.ts", - "cstring.d.ts", - "heap.d.ts" - ] -} \ No newline at end of file diff --git a/tests/binaryen.ts b/tests/binaryen.ts deleted file mode 100644 index 1c597094..00000000 --- a/tests/binaryen.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// - -import "../src/glue/js"; -import { NativeType, Module, MemorySegment, BinaryOp } from "../src/module"; -import { Target } from "../src/compiler"; -import { U64 } from "../src/util"; - -const mod = Module.create(); - -mod.setMemory(1, Module.MAX_MEMORY_WASM32, [ - MemorySegment.create(new Uint8Array(4), U64.fromI32(8)), - MemorySegment.create(new Uint8Array(4), U64.fromI32(12)) -], Target.WASM32, "memory"); - -const add = mod.addFunctionType("iii", NativeType.I32, [ NativeType.I32, NativeType.I32 ]); -mod.addFunction("add", add, [], mod.createReturn( - mod.createBinary(BinaryOp.AddI32, - mod.createGetLocal(0, NativeType.I32), - mod.createGetLocal(1, NativeType.I32) - ) -)); -mod.addFunctionExport("add", "add"); - -const lit = mod.addFunctionType("I", NativeType.I64, []); -mod.addFunction("lit", lit, [], mod.createReturn( - mod.createI64(0, 0x80000000) // I64_MIN -)); -mod.addFunctionExport("lit", "lit"); - -mod.addGlobal("42", NativeType.I32, false, mod.createI32(42)); - -const aSwitch = mod.addFunctionType("ii", NativeType.I32, [ NativeType.I32 ]); -const rl = mod.createRelooper(); -const b0 = rl.addBlockWithSwitch(mod.createNop(), mod.createGetLocal(0, NativeType.I32)); -let b1, b2, b3; -rl.addBranchForSwitch(b0, b2 = rl.addBlock(mod.createReturn(mod.createI32(1))), [1]); // indexed branch -rl.addBranchForSwitch(b0, b3 = rl.addBlock(mod.createReturn(mod.createI32(2))), [2]); // indexed branch -rl.addBranch(b0, b1 = rl.addBlock(mod.createDrop(mod.createI32(0)))); // default branch -rl.addBranch(b1, b2); - -mod.addFunction("aSwitch", aSwitch, [ NativeType.I32 ], mod.createBlock(null, [ - rl.renderAndDispose(b0, 1), - mod.createUnreachable() -])); -mod.addFunctionExport("aSwitch", "aSwitch"); - -// mod.optimize(); -if (mod.validate()) - _BinaryenModulePrint(mod.ref); -_BinaryenModuleDispose(mod.ref); diff --git a/tests/compiler.ts b/tests/compiler.js similarity index 63% rename from tests/compiler.ts rename to tests/compiler.js index e5486ed9..3b46c019 100644 --- a/tests/compiler.ts +++ b/tests/compiler.js @@ -1,16 +1,18 @@ -import * as fs from "fs"; -import * as path from "path"; -import * as chalk from "chalk"; -import * as glob from "glob"; +var fs = require("fs"); +var path = require("path"); +var chalk = require("chalk"); +var glob = require("glob"); +var diff = require("./util/diff"); -import "../src/glue/js"; -import { Compiler } from "../src/compiler"; -import { Module } from "../src/module"; -import { Parser } from "../src/parser"; -import { diff } from "./util/diff"; +require("ts-node").register({ project: require("path").join(__dirname, "..", "src") }); +require("../src/glue/js"); -const isCreate = process.argv[2] === "--create"; -const filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "*.ts"; +var Compiler = require("../src/compiler").Compiler; +var Module = require("../src/module").Module; +var Parser = require("../src/parser").Parser; + +var isCreate = process.argv[2] === "--create"; +var filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "*.ts"; glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => { if (filename.charAt(0) == "_" || filename.endsWith(".fixture.ts")) @@ -18,12 +20,12 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => { console.log(chalk.default.whiteBright("Testing compiler/" + filename)); - const parser = new Parser(); - const sourceText = fs.readFileSync(__dirname + "/compiler/" + filename, { encoding: "utf8" }); + var parser = new Parser(); + var sourceText = fs.readFileSync(__dirname + "/compiler/" + filename, { encoding: "utf8" }); parser.parseFile(sourceText, filename, true); - let nextFile; + var nextFile; while ((nextFile = parser.nextFile()) !== null) { - let nextSourceText: string; + var nextSourceText; try { nextSourceText = fs.readFileSync(path.join(__dirname, "compiler", nextFile + ".ts"), { encoding: "utf8" }); } catch (e) { @@ -31,12 +33,12 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => { } parser.parseFile(nextSourceText, nextFile, false); } - const program = parser.finish(); - const module = Compiler.compile(program); - const actual = module.toText() + "(;\n[program.elements]\n " + iterate(program.elements.keys()).join("\n ") + "\n[program.exports]\n " + iterate(program.exports.keys()).join("\n ") + "\n;)\n"; - let actualOptimized: string | null = null; - let actualInlined: string | null = null; - const fixture = path.basename(filename, ".ts") + ".wast"; + var program = parser.finish(); + var module = Compiler.compile(program); + var actual = module.toText() + "(;\n[program.elements]\n " + iterate(program.elements.keys()).join("\n ") + "\n[program.exports]\n " + iterate(program.exports.keys()).join("\n ") + "\n;)\n"; + var actualOptimized = null; + var actualInlined = null; + var fixture = path.basename(filename, ".ts") + ".wast"; if (module.validate()) { console.log(chalk.default.green("validate OK")); @@ -75,8 +77,8 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => { } } } else { - const expected = fs.readFileSync(__dirname + "/compiler/" + fixture, { encoding: "utf8" }); - const diffs = diff("compiler/" + fixture, expected, actual); + var expected = fs.readFileSync(__dirname + "/compiler/" + fixture, { encoding: "utf8" }); + var diffs = diff("compiler/" + fixture, expected, actual); if (diffs !== null) { process.exitCode = 1; console.log(diffs); @@ -90,11 +92,10 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => { console.log(); }); -function iterate(it: IterableIterator): T[] { - let current: IteratorResult; - var arr: T[] = []; - while ((current = it.next()) && !current.done) { +function iterate(it) { + var current; + var arr = []; + while ((current = it.next()) && !current.done) arr.push(current.value); - } return arr; -} \ No newline at end of file +} diff --git a/tests/parser.js b/tests/parser.js new file mode 100644 index 00000000..67b47d0e --- /dev/null +++ b/tests/parser.js @@ -0,0 +1,45 @@ +var fs = require("fs"); +var chalk = require("chalk"); +var glob = require("glob"); +var diff = require("./util/diff"); + +require("ts-node").register({ project: require("path").join(__dirname, "..", "src", "tsconfig.json") }); +require("../src/glue/js"); + +var Parser = require("../src/parser").Parser; + +var isCreate = process.argv[2] === "--create"; +var filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "**.ts"; + +glob.sync(filter, { cwd: __dirname + "/parser" }).forEach(filename => { + if (filename.charAt(0) == "_" || filename.endsWith(".fixture.ts")) + return; + + console.log(chalk.default.whiteBright("Testing parser/" + filename)); + + var parser = new Parser(); + var sourceText = fs.readFileSync(__dirname + "/parser/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, ""); + parser.parseFile(sourceText, filename, true); + + var sb = []; + parser.program.sources[0].serialize(sb); + var actual = sb.join(""); + var fixture = filename + ".fixture.ts"; + + if (isCreate) { + fs.writeFileSync(__dirname + "/parser/" + fixture, actual, { encoding: "utf8" }); + console.log("Created\n"); + } else { + var expected = fs.readFileSync(__dirname + "/parser/" + fixture, { encoding: "utf8" }); + var diffs = diff("parser/" + fixture, expected, actual); + if (diffs !== null) { + process.exitCode = 1; + console.log(diffs); + console.log(chalk.default.red("diff ERROR")); + } else { + console.log(chalk.default.green("diff OK")); + } + } + + console.log(); +}); diff --git a/tests/parser.ts b/tests/parser.ts deleted file mode 100644 index fbe7114a..00000000 --- a/tests/parser.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as fs from "fs"; -import * as chalk from "chalk"; -import * as glob from "glob"; - -import "../src/glue/js"; -import { Parser } from "../src/parser"; -import { diff } from "./util/diff"; - -const isCreate = process.argv[2] === "--create"; -const filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "**.ts"; - -glob.sync(filter, { cwd: __dirname + "/parser" }).forEach(filename => { - if (filename.charAt(0) == "_" || filename.endsWith(".fixture.ts")) - return; - - console.log(chalk.default.whiteBright("Testing parser/" + filename)); - - const parser = new Parser(); - const sourceText = fs.readFileSync(__dirname + "/parser/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, ""); - parser.parseFile(sourceText, filename, true); - - var sb: string[] = []; - parser.program.sources[0].serialize(sb); - const actual = sb.join(""); - const fixture = filename + ".fixture.ts"; - - if (isCreate) { - fs.writeFileSync(__dirname + "/parser/" + fixture, actual, { encoding: "utf8" }); - console.log("Created\n"); - } else { - const expected = fs.readFileSync(__dirname + "/parser/" + fixture, { encoding: "utf8" }); - const diffs = diff("parser/" + fixture, expected, actual); - if (diffs !== null) { - process.exitCode = 1; - console.log(diffs); - console.log(chalk.default.red("diff ERROR")); - } else { - console.log(chalk.default.green("diff OK")); - } - } - - console.log(); -}); diff --git a/tests/util/diff.ts b/tests/util/diff.js similarity index 57% rename from tests/util/diff.ts rename to tests/util/diff.js index e027647e..108055b0 100644 --- a/tests/util/diff.ts +++ b/tests/util/diff.js @@ -1,17 +1,17 @@ -import * as JsDiff from "diff"; -import * as chalk from "chalk"; +var JsDiff = require("diff"); +var chalk = require("chalk"); -export function diff(filename: string, expected: string, actual: string): string | null { - const diff = JsDiff.structuredPatch(filename, filename, expected, actual, "expected", "actual", { context: 2 }); +module.exports = function diff(filename, expected, actual) { + var diff = JsDiff.structuredPatch(filename, filename, expected, actual, "expected", "actual", { context: 2 }); if (!diff.hunks.length) return null; - const ret = []; + var ret = []; ret.push('--- ' + diff.oldHeader); ret.push('+++ ' + diff.newHeader); - for (let i = 0; i < diff.hunks.length; i++) { - const hunk = diff.hunks[i]; + for (var i = 0; i < diff.hunks.length; i++) { + var hunk = diff.hunks[i]; ret.push( '@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines @@ -27,4 +27,4 @@ export function diff(filename: string, expected: string, actual: string): string } return ret.join('\n') + '\n'; -} +}; diff --git a/tsconfig-base.json b/tsconfig-base.json new file mode 100644 index 00000000..415a5fb8 --- /dev/null +++ b/tsconfig-base.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noEmitOnError": true, + "strictNullChecks": true, + "experimentalDecorators": true + } +}