mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-24 14:42:13 +00:00
Minor restructure and fixes; README; Proposed binaryen additions
This commit is contained in:
parent
5ff88e126e
commit
0228ab91d9
72
README.md
72
README.md
@ -3,63 +3,34 @@ AssemblyScript NEXT
|
||||
|
||||
[](https://travis-ci.org/AssemblyScript/next)
|
||||
|
||||
This repository contains compiler components for the next iteration of the AssemblyScript compiler written in AssemblyScript itself.
|
||||
**AssemblyScript** is a new compiler targeting WebAssembly while utilizing [TypeScript](http://www.typescriptlang.org)'s syntax and [node](https://nodejs.org)'s vibrant ecosystem. Instead of requiring complex toolchains to set up, you can simply `npm install` it - or run it in a browser.
|
||||
|
||||
Note that the code uses some features and standard library components that are not yet supported by any version of asc. To account for this, the code has been written in "portable AssemblyScript", a TypeScript-compatible subset of a subset of a superset of JavaScript, that also compiles to JavaScript using TSC.
|
||||
By compiling a variant of TypeScript to [Binaryen](https://github.com/WebAssembly/binaryen) IR, the resulting module can be validated, optimized, emitted in WebAssembly text or binary format and converted to [asm.js](http://asmjs.org) as a polyfill.
|
||||
|
||||
Why is this necessary?
|
||||
----------------------
|
||||
The compiler itself is written in "portable AssemblyScript" so it can be compiled to both JavaScript using `tsc` and, eventually, to WebAssembly using `asc`.
|
||||
|
||||
Well, it isn't, but: In order to be able to compile the AssemblyScript compiler itself to WebAssembly eventually, we cannot depend on TypeScript because it is written in vanilla TypeScript and makes use of quite a few non-AOT-compatible dynamic features of JavaScript.
|
||||
Development status
|
||||
------------------
|
||||
|
||||
Cons:
|
||||
- A lot of work
|
||||
- Dealing with TypeScript compatibility issues
|
||||
|
||||
Pros:
|
||||
- One day compiling to WebAssembly for performance
|
||||
- Necessary features only, reducing binary size
|
||||
- Linking against Binaryen compiled to WebAssembly, reducing overhead
|
||||
|
||||
Side effects:
|
||||
- Good fire test for the compiler
|
||||
- Good benchmark when comparing both versions
|
||||
- Benefits standard library design ideas
|
||||
|
||||
How does it work?
|
||||
-----------------
|
||||
|
||||
AssemblyScript NEXT compiles a subset (or variant) of TypeScript to [Binaryen](https://github.com/WebAssembly/binaryen) IR. The resulting module can then be optimized, emitted in text or binary format or converted to [asm.js](http://asmjs.org) as a polyfill.
|
||||
This version of the compiler (0.5.0, NEXT) is relatively new and does not yet support some features a TypeScript programmer might expect, e.g., strings, arrays and classes. For now, you can see the [compiler tests](https://github.com/AssemblyScript/next/tree/master/tests/compiler) for an overview of what's supposed to be working already.
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
If you'd like to try out NEXT today or even plan to contribute, this is how you do it:
|
||||
If you'd like to try it today or even plan to contribute, this is how you do it:
|
||||
|
||||
```
|
||||
$> git clone https://github.com/AssemblyScript/next.git
|
||||
$> cd next
|
||||
$> npm install
|
||||
```
|
||||
|
||||
Author your module in AssemblyScript ([definitions](./assembly.d.ts)) or portable AssemblyScript ([definitions](./portable-assembly.d.ts)) and run:
|
||||
|
||||
```
|
||||
$> node bin\asc yourModule.ts
|
||||
```
|
||||
|
||||
Building an UMD bundle to `dist/assemblyscript.js` (does not bundle [binaryen.js](https://github.com/AssemblyScript/binaryen.js)):
|
||||
|
||||
```
|
||||
$> npm run build
|
||||
```
|
||||
|
||||
Running the [tests](./tests):
|
||||
|
||||
```
|
||||
$> npm test
|
||||
```
|
||||
|
||||
Development status
|
||||
------------------
|
||||
|
||||
For now, see the [compiler tests](https://github.com/AssemblyScript/next/tree/master/tests/compiler) for an overview of what's supposed to be working already.
|
||||
|
||||
Using the CLI
|
||||
-------------
|
||||
|
||||
@ -82,9 +53,24 @@ Options:
|
||||
--noTreeShaking Disables tree-shaking.
|
||||
--noDebug Disables assertions.
|
||||
--trapMode Sets the trap mode to use.
|
||||
none Do not modify trapping operations. This is the default.
|
||||
allow Allow trapping operations. This is the default.
|
||||
clamp Replace trapping operations with clamping semantics.
|
||||
js Replace trapping operations with JS semantics.
|
||||
```
|
||||
|
||||
Unless a bundle has been built to `dist/`, `asc` runs the TypeScript sources directly via [ts-node](https://www.npmjs.com/package/ts-node). Useful for development.
|
||||
Unless a bundle has been built to `dist/`, `asc` runs the TypeScript sources on the fly via [ts-node](https://www.npmjs.com/package/ts-node). Useful for development.
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
Building an UMD bundle to `dist/assemblyscript.js` (does not bundle [binaryen.js](https://github.com/AssemblyScript/binaryen.js)):
|
||||
|
||||
```
|
||||
$> npm run build
|
||||
```
|
||||
|
||||
Running the [tests](./tests):
|
||||
|
||||
```
|
||||
$> npm test
|
||||
```
|
||||
|
4
assembly.d.ts
vendored
4
assembly.d.ts
vendored
@ -89,7 +89,7 @@ declare function isFinite<T = f32 | f64>(value: T): bool;
|
||||
/** Traps if the specified value evaluates to `false`. */
|
||||
declare function assert(isTrue: bool): void;
|
||||
|
||||
// Internal decorators
|
||||
// Internal decorators (not yet implemented)
|
||||
|
||||
/** Annotates an element being part of the global namespace. */
|
||||
declare function global(): any;
|
||||
@ -98,7 +98,7 @@ declare function inline(): any;
|
||||
/** Annotates a class using a C-style memory layout. */
|
||||
declare function struct(): any;
|
||||
|
||||
// Standard library
|
||||
// Standard library (not yet implemented)
|
||||
|
||||
/// <reference path="./std/carray.d.ts" />
|
||||
/// <reference path="./std/cstring.d.ts" />
|
||||
|
@ -66,7 +66,7 @@ if (args.help || args._.length < 1) {
|
||||
"",
|
||||
"Examples: asc hello.ts",
|
||||
" asc hello.ts -b hello.wasm -t hello.wast -a hello.js",
|
||||
" asc hello.ts -b > hello.wasm",
|
||||
" asc hello1.ts hello2.ts -b -O > hello.wasm",
|
||||
"",
|
||||
"Options:"
|
||||
].concat(options).join("\n"));
|
||||
@ -145,6 +145,10 @@ if (args.trapMode === "clamp")
|
||||
module.runPasses([ "trap-mode-clamp" ]);
|
||||
else if (args.trapMode === "js")
|
||||
module.runPasses([ "trap-mode-js" ]);
|
||||
else if (args.trapMode !== "allow") {
|
||||
console.log("Unsupported trap mode: " + args.trapMode);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (args.optimize)
|
||||
module.optimize();
|
||||
|
@ -50,11 +50,11 @@
|
||||
"trapMode": {
|
||||
"desc": [
|
||||
"Sets the trap mode to use.",
|
||||
"none Do not modify trapping operations. This is the default.",
|
||||
"allow Allow trapping operations. This is the default.",
|
||||
"clamp Replace trapping operations with clamping semantics.",
|
||||
"js Replace trapping operations with JS semantics."
|
||||
],
|
||||
"type": "string",
|
||||
"default": "none"
|
||||
"default": "allow"
|
||||
}
|
||||
}
|
||||
|
1
index.d.ts
vendored
Normal file
1
index.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export * from "./src";
|
10
package.json
10
package.json
@ -31,7 +31,8 @@
|
||||
"typescript": "^2.6.2",
|
||||
"webpack": "^3.10.0"
|
||||
},
|
||||
"main": "dist/assemblyscript.js",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"bin": {
|
||||
"asc": "bin/asc.js"
|
||||
},
|
||||
@ -48,10 +49,15 @@
|
||||
"bin/asc.json",
|
||||
"dist/assemblyscript.js",
|
||||
"dist/assemblyscript.js.map",
|
||||
"index.d.ts",
|
||||
"index.js",
|
||||
"LICENSE",
|
||||
"NOTICE",
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"README.md"
|
||||
"portable-assembly.d.ts",
|
||||
"portable-assembly.js",
|
||||
"README.md",
|
||||
"src"
|
||||
]
|
||||
}
|
||||
|
2
portable-assembly.d.ts
vendored
2
portable-assembly.d.ts
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
// Portable types
|
||||
|
||||
// Note that semantics differences require additional explicit conversions for full compatibility.
|
||||
// Note that semantic differences require additional explicit conversions for full compatibility.
|
||||
// For example, when casting an i32 to an u8, doing `<u8>(someI32 & 0xff)` will yield the same
|
||||
// result when compiling to WebAssembly or JS while `<u8>someI32` alone does nothing in JS.
|
||||
|
||||
|
139
src/compiler.ts
139
src/compiler.ts
@ -1,8 +1,56 @@
|
||||
import { compileCall as compileBuiltinCall, initialize } from "./builtins";
|
||||
import { PATH_DELIMITER } from "./constants";
|
||||
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
|
||||
import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, NativeType, FunctionRef, FunctionTypeRef, getExpressionId, ExpressionId, getExpressionType, getFunctionBody, getConstValueI32, getConstValueI64Low, getConstValueI64High, getConstValueF32, getConstValueF64 } from "./module";
|
||||
import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter, EnumValue } from "./program";
|
||||
import {
|
||||
|
||||
Module,
|
||||
MemorySegment,
|
||||
ExpressionRef,
|
||||
UnaryOp,
|
||||
BinaryOp,
|
||||
NativeType,
|
||||
FunctionTypeRef,
|
||||
FunctionRef,
|
||||
ExpressionId,
|
||||
|
||||
getExpressionId,
|
||||
getExpressionType,
|
||||
getFunctionBody,
|
||||
getConstValueI32,
|
||||
getConstValueI64Low,
|
||||
getConstValueI64High,
|
||||
getConstValueF32,
|
||||
getConstValueF64,
|
||||
getGetLocalIndex,
|
||||
getGetGlobalName,
|
||||
isLoadAtomic,
|
||||
isLoadSigned,
|
||||
getLoadBytes,
|
||||
getLoadOffset,
|
||||
getLoadPtr,
|
||||
getUnaryOp,
|
||||
getUnaryValue,
|
||||
getBinaryOp,
|
||||
getBinaryLeft,
|
||||
getBinaryRight
|
||||
|
||||
} from "./module";
|
||||
import {
|
||||
|
||||
Program,
|
||||
ClassPrototype,
|
||||
Class, Element,
|
||||
ElementKind,
|
||||
Enum,
|
||||
FunctionPrototype,
|
||||
Function,
|
||||
Global,
|
||||
Local,
|
||||
Namespace,
|
||||
Parameter,
|
||||
EnumValue
|
||||
|
||||
} from "./program";
|
||||
import { I64, U64, sb } from "./util";
|
||||
import { Token } from "./tokenizer";
|
||||
import {
|
||||
@ -65,6 +113,7 @@ import {
|
||||
UnaryPostfixExpression,
|
||||
UnaryPrefixExpression,
|
||||
|
||||
// utility
|
||||
hasModifier
|
||||
|
||||
} from "./ast";
|
||||
@ -1021,7 +1070,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.module.runPasses([ "precompute" ], funcRef);
|
||||
const ret: ExpressionRef = getFunctionBody(funcRef);
|
||||
this.module.removeFunction("__precompute");
|
||||
// TODO: also remove the function type somehow if no longer used
|
||||
// TODO: also remove the function type somehow if no longer used or make the C-API accept
|
||||
// a `null` typeRef, using an implicit type.
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1190,6 +1240,41 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return expr;
|
||||
}
|
||||
|
||||
cloneExpressionRef(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = 0x7fffffff): ExpressionRef {
|
||||
// currently supports side effect free expressions only
|
||||
if (maxDepth < 0)
|
||||
return 0;
|
||||
let nested1: ExpressionRef,
|
||||
nested2: ExpressionRef;
|
||||
switch (getExpressionId(expr)) {
|
||||
case ExpressionId.Const:
|
||||
switch (getExpressionType(expr)) {
|
||||
case NativeType.I32: return this.module.createI32(getConstValueI32(expr));
|
||||
case NativeType.I64: return this.module.createI64(getConstValueI64Low(expr), getConstValueI64High(expr));
|
||||
case NativeType.F32: return this.module.createF32(getConstValueF32(expr));
|
||||
case NativeType.F64: return this.module.createF64(getConstValueF64(expr));
|
||||
default: throw new Error("unexpected expression type");
|
||||
}
|
||||
case ExpressionId.GetLocal:
|
||||
return this.module.createGetLocal(getGetLocalIndex(expr), getExpressionType(expr));
|
||||
case ExpressionId.GetGlobal:
|
||||
return this.module.createGetGlobal(getGetGlobalName(expr), getExpressionType(expr));
|
||||
case ExpressionId.Load:
|
||||
if (!(nested1 = this.cloneExpressionRef(getLoadPtr(expr), noSideEffects, maxDepth - 1))) break;
|
||||
return isLoadAtomic(expr)
|
||||
? this.module.createAtomicLoad(getLoadBytes(expr), nested1, getExpressionType(expr), getLoadOffset(expr))
|
||||
: this.module.createLoad(getLoadBytes(expr), isLoadSigned(expr), nested1, getExpressionType(expr), getLoadOffset(expr));
|
||||
case ExpressionId.Unary:
|
||||
if (!(nested1 = this.cloneExpressionRef(getUnaryValue(expr), noSideEffects, maxDepth - 1))) break;
|
||||
return this.module.createUnary(getUnaryOp(expr), nested1);
|
||||
case ExpressionId.Binary:
|
||||
if (!(nested1 = this.cloneExpressionRef(getBinaryLeft(expr), noSideEffects, maxDepth - 1))) break;
|
||||
if (!(nested2 = this.cloneExpressionRef(getBinaryLeft(expr), noSideEffects, maxDepth - 1))) break;
|
||||
return this.module.createBinary(getBinaryOp(expr), nested1, nested2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
|
||||
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
|
||||
return toType && toType != contextualType
|
||||
@ -1426,15 +1511,31 @@ export class Compiler extends DiagnosticEmitter {
|
||||
case Token.AMPERSAND_AMPERSAND: // left && right
|
||||
left = this.compileExpression(expression.left, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
|
||||
right = this.compileExpression(expression.right, this.currentType);
|
||||
// TODO: once it's possible to clone 'left', we could check if it is a Const, GetLocal, GetGlobal or Load and avoid the tempLocal
|
||||
|
||||
// simplify if left is free of side effects while tolerating two levels of nesting, e.g., i32.load(i32.load(i32.const))
|
||||
// if (condition = this.cloneExpressionRef(left, true, 2))
|
||||
// return this.module.createIf(
|
||||
// this.currentType.isLongInteger
|
||||
// ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))
|
||||
// : this.currentType == Type.f64
|
||||
// ? this.module.createBinary(BinaryOp.NeF64, condition, this.module.createF64(0))
|
||||
// : this.currentType == Type.f32
|
||||
// ? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
|
||||
// : condition, // usual case: saves one EQZ when not using EQZ above
|
||||
// right,
|
||||
// left
|
||||
// );
|
||||
|
||||
// otherwise use a temporary local for the intermediate value
|
||||
tempLocal = this.currentFunction.addLocal(this.currentType);
|
||||
condition = this.module.createTeeLocal(tempLocal.index, left);
|
||||
return this.module.createIf(
|
||||
this.currentType.isLongInteger
|
||||
? this.module.createBinary(BinaryOp.NeI64, this.module.createTeeLocal(tempLocal.index, left), this.module.createI64(0, 0))
|
||||
? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))
|
||||
: this.currentType == Type.f64
|
||||
? this.module.createBinary(BinaryOp.NeF64, this.module.createTeeLocal(tempLocal.index, left), this.module.createF64(0))
|
||||
? this.module.createBinary(BinaryOp.NeF64, condition, this.module.createF64(0))
|
||||
: this.currentType == Type.f32
|
||||
? this.module.createBinary(BinaryOp.NeF32, this.module.createTeeLocal(tempLocal.index, left), this.module.createF32(0))
|
||||
? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
|
||||
: this.module.createTeeLocal(tempLocal.index, left),
|
||||
right,
|
||||
this.module.createGetLocal(tempLocal.index, typeToNativeType(tempLocal.type))
|
||||
@ -1443,15 +1544,31 @@ export class Compiler extends DiagnosticEmitter {
|
||||
case Token.BAR_BAR: // left || right
|
||||
left = this.compileExpression(expression.left, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
|
||||
right = this.compileExpression(expression.right, this.currentType);
|
||||
// TODO: same as above
|
||||
|
||||
// simplify if left is free of side effects while tolerating two levels of nesting
|
||||
// if (condition = this.cloneExpressionRef(left, true, 2))
|
||||
// return this.module.createIf(
|
||||
// this.currentType.isLongInteger
|
||||
// ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))
|
||||
// : this.currentType == Type.f64
|
||||
// ? this.module.createBinary(BinaryOp.NeF64, condition, this.module.createF64(0))
|
||||
// : this.currentType == Type.f32
|
||||
// ? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
|
||||
// : condition, // usual case: saves one EQZ when not using EQZ above
|
||||
// left,
|
||||
// right
|
||||
// );
|
||||
|
||||
// otherwise use a temporary local for the intermediate value
|
||||
tempLocal = this.currentFunction.addLocal(this.currentType);
|
||||
condition = this.module.createTeeLocal(tempLocal.index, left);
|
||||
return this.module.createIf(
|
||||
this.currentType.isLongInteger
|
||||
? this.module.createBinary(BinaryOp.NeI64, this.module.createTeeLocal(tempLocal.index, left), this.module.createI64(0, 0))
|
||||
? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))
|
||||
: this.currentType == Type.f64
|
||||
? this.module.createBinary(BinaryOp.NeF64, this.module.createTeeLocal(tempLocal.index, left), this.module.createF64(0))
|
||||
? this.module.createBinary(BinaryOp.NeF64, condition, this.module.createF64(0))
|
||||
: this.currentType == Type.f32
|
||||
? this.module.createBinary(BinaryOp.NeF32, this.module.createTeeLocal(tempLocal.index, left), this.module.createF32(0))
|
||||
? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
|
||||
: this.module.createTeeLocal(tempLocal.index, left),
|
||||
this.module.createGetLocal(tempLocal.index, typeToNativeType(tempLocal.type)),
|
||||
right
|
||||
|
120
src/glue/binaryen-c.d.ts
vendored
120
src/glue/binaryen-c.d.ts
vendored
@ -60,13 +60,9 @@ declare type BinaryenModuleRef = usize;
|
||||
declare function _BinaryenModuleCreate(): BinaryenModuleRef;
|
||||
declare function _BinaryenModuleDispose(module: BinaryenModuleRef): void;
|
||||
|
||||
declare type BinaryenFunctionTypeRef = usize;
|
||||
declare type CString = usize;
|
||||
declare type CArray<T> = usize;
|
||||
|
||||
declare function _BinaryenAddFunctionType(module: BinaryenModuleRef, name: CString, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
declare function _BinaryenGetFunctionTypeBySignature(module: BinaryenModuleRef, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
|
||||
declare type BinaryenLiteral = CArray<u8>;
|
||||
|
||||
// LLVM C ABI with `out` being a buffer of 16 bytes receiving the BinaryenLiteral struct.
|
||||
@ -256,18 +252,134 @@ declare function _BinaryenAtomicWake(module: BinaryenModuleRef, ptr: BinaryenExp
|
||||
declare function _BinaryenExpressionGetId(expr: BinaryenExpressionRef): BinaryenExpressionId;
|
||||
declare function _BinaryenExpressionGetType(expr: BinaryenExpressionRef): BinaryenType;
|
||||
declare function _BinaryenExpressionPrint(expr: BinaryenExpressionRef): void;
|
||||
|
||||
declare function _BinaryenBlockGetName(expr: BinaryenExpressionRef): CString;
|
||||
declare function _BinaryenBlockGetNumChildren(expr: BinaryenExpressionRef): BinaryenIndex;
|
||||
declare function _BinaryenBlockGetChild(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenIfGetCondition(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenIfGetIfTrue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenIfGetIfFalse(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenLoopGetName(expr: BinaryenExpressionRef): CString;
|
||||
declare function _BinaryenLoopGetBody(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenBreakGetName(expr: BinaryenExpressionRef): CString;
|
||||
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 _BinaryenSwitchGetCondition(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenSwitchGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenCallGetTarget(expr: BinaryenExpressionRef): CString;
|
||||
declare function _BinaryenCallGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex;
|
||||
declare function _BinaryenCallGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenCallImportGetTarget(expr: BinaryenExpressionRef): CString;
|
||||
declare function _BinaryenCallImportGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex;
|
||||
declare function _BinaryenCallImportGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenCallIndirectGetTarget(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenCallIndirectGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex;
|
||||
declare function _BinaryenCallIndirectGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenGetLocalGetIndex(expr: BinaryenExpressionRef): BinaryenIndex;
|
||||
|
||||
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 _BinaryenSetGlobalGetName(expr: BinaryenExpressionRef): CString;
|
||||
declare function _BinaryenSetGlobalGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenHostGetOp(expr: BinaryenExpressionRef): BinaryenOp;
|
||||
declare function _BinaryenHostGetNameOperand(expr: BinaryenExpressionRef): CString;
|
||||
declare function _BinaryenHostGetNumOperands(expr: BinaryenExpressionRef): BinaryenIndex;
|
||||
declare function _BinaryenHostGetOperand(expr: BinaryenExpressionRef, index: BinaryenIndex): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenLoadIsAtomic(expr: BinaryenExpressionRef): bool;
|
||||
declare function _BinaryenLoadIsSigned(expr: BinaryenExpressionRef): bool;
|
||||
declare function _BinaryenLoadGetBytes(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenLoadGetOffset(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenLoadGetAlign(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenLoadGetPtr(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenStoreIsAtomic(expr: BinaryenExpressionRef): bool;
|
||||
declare function _BinaryenStoreGetBytes(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenStoreGetOffset(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenStoreGetAlign(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenStoreGetPtr(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenStoreGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenConstGetValueI32(expr: BinaryenExpressionRef): i32;
|
||||
declare function _BinaryenConstGetValueI64Low(expr: BinaryenExpressionRef): i32;
|
||||
declare function _BinaryenConstGetValueI64High(expr: BinaryenExpressionRef): i32;
|
||||
declare function _BinaryenConstGetValueF32(expr: BinaryenExpressionRef): f32;
|
||||
declare function _BinaryenConstGetValueF64(expr: BinaryenExpressionRef): f64;
|
||||
|
||||
declare function _BinaryenUnaryGetOp(expr: BinaryenExpressionRef): BinaryenOp;
|
||||
declare function _BinaryenUnaryGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenBinaryGetOp(expr: BinaryenExpressionRef): BinaryenOp;
|
||||
declare function _BinaryenBinaryGetLeft(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenBinaryGetRight(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenSelectGetIfTrue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenSelectGetIfFalse(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenSelectGetCondition(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenDropGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenReturnGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenAtomicRMWGetOp(expr: BinaryenExpressionRef): BinaryenOp;
|
||||
declare function _BinaryenAtomicRMWGetBytes(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenAtomicRMWGetOffset(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenAtomicRMWGetPtr(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicRMWGetValue(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenAtomicCmpxchgGetBytes(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenAtomicCmpxchgGetOffset(expr: BinaryenExpressionRef): u32;
|
||||
declare function _BinaryenAtomicCmpxchgGetPtr(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicCmpxchgGetExpected(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicCmpxchgGetReplacement(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenAtomicWaitGetPtr(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicWaitGetExpected(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicWaitGetTimeout(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicWaitGetExpectedType(expr: BinaryenExpressionRef): BinaryenType;
|
||||
|
||||
declare function _BinaryenAtomicWakeGetPtr(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicWakeGetWakeCount(expr: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare type BinaryenFunctionTypeRef = usize;
|
||||
|
||||
declare function _BinaryenAddFunctionType(module: BinaryenModuleRef, name: CString, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
declare function _BinaryenGetFunctionTypeBySignature(module: BinaryenModuleRef, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
|
||||
declare function _BinaryenFunctionTypeGetName(ftype: BinaryenFunctionTypeRef): CString;
|
||||
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<BinaryenType>, numVarTypes: BinaryenIndex, body: BinaryenExpressionRef): BinaryenFunctionRef;
|
||||
declare function _BinaryenGetFunction(module: BinaryenModuleRef, name: CString): BinaryenFunctionRef;
|
||||
declare function _BinaryenRemoveFunction(module: BinaryenModuleRef, name: CString): void;
|
||||
|
||||
declare function _BinaryenFunctionGetName(func: BinaryenFunctionRef): CString;
|
||||
declare function _BinaryenFunctionGetType(func: BinaryenFunctionRef): BinaryenFunctionTypeRef;
|
||||
declare function _BinaryenFunctionGetNumParams(func: BinaryenFunctionRef): BinaryenIndex;
|
||||
declare function _BinaryenFunctionGetParam(func: BinaryenFunctionRef, index: BinaryenIndex): BinaryenType;
|
||||
declare function _BinaryenFunctionGetResult(func: BinaryenFunctionRef): BinaryenType;
|
||||
declare function _BinaryenFunctionGetNumVars(func: BinaryenFunctionRef): BinaryenIndex;
|
||||
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<CString>, numPasses: BinaryenIndex): void;
|
||||
|
@ -807,10 +807,58 @@ export function getConstValueF64(expr: ExpressionRef): f64 {
|
||||
return _BinaryenConstGetValueF64(expr);
|
||||
}
|
||||
|
||||
export function getGetLocalIndex(expr: ExpressionRef): Index {
|
||||
return _BinaryenGetLocalGetIndex(expr);
|
||||
}
|
||||
|
||||
export function getGetGlobalName(expr: ExpressionRef): string {
|
||||
return readString(_BinaryenGetGlobalGetName(expr));
|
||||
}
|
||||
|
||||
export function isLoadAtomic(expr: ExpressionRef): bool {
|
||||
return _BinaryenLoadIsAtomic(expr);
|
||||
}
|
||||
|
||||
export function isLoadSigned(expr: ExpressionRef): bool {
|
||||
return _BinaryenLoadIsSigned(expr);
|
||||
}
|
||||
|
||||
export function getLoadBytes(expr: ExpressionRef): u32 {
|
||||
return _BinaryenLoadGetBytes(expr);
|
||||
}
|
||||
|
||||
export function getLoadOffset(expr: ExpressionRef): u32 {
|
||||
return _BinaryenLoadGetOffset(expr);
|
||||
}
|
||||
|
||||
export function getLoadPtr(expr: ExpressionRef): ExpressionRef {
|
||||
return _BinaryenLoadGetPtr(expr);
|
||||
}
|
||||
|
||||
export function getFunctionBody(func: FunctionRef): ExpressionRef {
|
||||
return _BinaryenFunctionGetBody(func);
|
||||
}
|
||||
|
||||
export function getUnaryOp(expr: ExpressionRef): UnaryOp {
|
||||
return _BinaryenUnaryGetOp(expr);
|
||||
}
|
||||
|
||||
export function getUnaryValue(expr: ExpressionRef): ExpressionRef {
|
||||
return _BinaryenUnaryGetValue(expr);
|
||||
}
|
||||
|
||||
export function getBinaryOp(expr: ExpressionRef): BinaryOp {
|
||||
return _BinaryenBinaryGetOp(expr);
|
||||
}
|
||||
|
||||
export function getBinaryLeft(expr: ExpressionRef): ExpressionRef {
|
||||
return _BinaryenBinaryGetLeft(expr);
|
||||
}
|
||||
|
||||
export function getBinaryRight(expr: ExpressionRef): ExpressionRef {
|
||||
return _BinaryenBinaryGetRight(expr);
|
||||
}
|
||||
|
||||
export class Relooper {
|
||||
|
||||
module: Module;
|
||||
@ -866,9 +914,9 @@ export class Relooper {
|
||||
}
|
||||
}
|
||||
|
||||
// export function setAPITracing(on: bool): void {
|
||||
// _BinaryenSetAPITracing(on ? 1 : 0);
|
||||
// }
|
||||
export function setAPITracing(on: bool): void {
|
||||
_BinaryenSetAPITracing(on ? 1 : 0);
|
||||
}
|
||||
|
||||
// helpers
|
||||
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js
|
||||
@ -959,3 +1007,47 @@ function allocString(str: string | null): CString {
|
||||
store<u8>(idx, 0);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function readString(ptr: usize): string {
|
||||
const utf16le: u32[] = [];
|
||||
// the following is based on Emscripten's UTF8ArrayToString
|
||||
let cp: u32;
|
||||
let u1: u32, u2: u32, u3: u32, u4: u32, u5: u32;
|
||||
while (cp = load<u8>(ptr++)) {
|
||||
if (!(cp & 0x80)) {
|
||||
utf16le.push(cp);
|
||||
continue;
|
||||
}
|
||||
u1 = load<u8>(ptr++) & 63;
|
||||
if ((cp & 0xE0) == 0xC0) {
|
||||
utf16le.push(((cp & 31) << 6) | u1);
|
||||
continue;
|
||||
}
|
||||
u2 = load<u8>(ptr++) & 63;
|
||||
if ((cp & 0xF0) == 0xE0) {
|
||||
cp = ((cp & 15) << 12) | (u1 << 6) | u2;
|
||||
} else {
|
||||
u3 = load<u8>(ptr++) & 63;
|
||||
if ((cp & 0xF8) == 0xF0) {
|
||||
cp = ((cp & 7) << 18) | (u1 << 12) | (u2 << 6) | u3;
|
||||
} else {
|
||||
u4 = load<u8>(ptr++) & 63;
|
||||
if ((cp & 0xFC) == 0xF8) {
|
||||
cp = ((cp & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4;
|
||||
} else {
|
||||
u5 = load<u8>(ptr++) & 63;
|
||||
cp = ((cp & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cp < 0x10000) {
|
||||
utf16le.push(cp);
|
||||
} else {
|
||||
var ch = cp - 0x10000;
|
||||
utf16le.push(0xD800 | (ch >> 10));
|
||||
utf16le.push(0xDC00 | (ch & 0x3FF));
|
||||
}
|
||||
}
|
||||
// FIXME: not portable and prone to stack overflows. Maybe use CString from stdlib?
|
||||
return String.fromCharCode.apply(utf16le);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ export class Type {
|
||||
constructor(kind: TypeKind, size: i32) {
|
||||
this.kind = kind;
|
||||
this.size = size;
|
||||
this.byteSize = ceil<f64>(<f64>size / 8);
|
||||
this.byteSize = <i32>ceil<f64>(<f64>size / 8);
|
||||
this.classType = null;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ fetch("game-of-life.optimized.wast").then(response => response.text()).then(text
|
||||
s = w * h, // memory required to store either input or output
|
||||
S = s + s; // total memory required to store input and output
|
||||
|
||||
// Grow the (exported) memory if it's size isn't sufficient
|
||||
// Grow the (exported) memory if its size isn't sufficient
|
||||
var memory = instance.exports.memory;
|
||||
if (memory.buffer.byteLength < S)
|
||||
memory.grow(Math.ceil((S - memory.buffer.byteLength) / 65536));
|
||||
@ -27,7 +27,7 @@ fetch("game-of-life.optimized.wast").then(response => response.text()).then(text
|
||||
// Initialize with width and height
|
||||
instance.exports.init(w, h);
|
||||
|
||||
// Fill input at [0, s-1] with random cells
|
||||
// Fill input at [0, s-1] with random live cells
|
||||
var mem = new Uint8Array(memory.buffer);
|
||||
for (var y = 0; y < h; ++y)
|
||||
for (var x = 0; x < w; ++x)
|
||||
|
Loading…
x
Reference in New Issue
Block a user