diff --git a/README.md b/README.md
index b561ab2a..9f1ea02c 100644
--- a/README.md
+++ b/README.md
@@ -20,10 +20,10 @@ A few early examples to get an idea:
A PSON decoder implemented in AssemblyScript.
* **[TLSF memory allocator](./examples/tlsf)**
- An port of TLSF to AssemblyScript.
+ A port of TLSF to AssemblyScript.
* **[μgc garbage collector](./examples/ugc)**
- An port of μgc to AssemblyScript.
+ A port of μgc to AssemblyScript.
Or browse the [compiler tests](./tests/compiler) for a more in-depth overview of what's supported already. One of them is a [showcase](./tests/compiler/showcase.ts).
diff --git a/bin/asc.js b/bin/asc.js
index 7f150156..6ab7a97c 100644
--- a/bin/asc.js
+++ b/bin/asc.js
@@ -32,7 +32,7 @@ Object.keys(conf).forEach(key => {
var args = minimist(process.argv.slice(2), opts);
var version = require("../package.json").version;
-var indent = 20;
+var indent = 24;
if (isDev) version += "-dev";
if (args.version) {
@@ -47,9 +47,9 @@ if (args.help || args._.length < 1) {
Object.keys(conf).forEach(name => {
var option = conf[name];
var text = " ";
- if (option.aliases && option.aliases[0].length === 1)
- text += "-" + option.aliases[0] + ", ";
text += "--" + name;
+ if (option.aliases && option.aliases[0].length === 1)
+ text += ", -" + option.aliases[0];
while (text.length < indent)
text += " ";
if (Array.isArray(option.desc)) {
@@ -164,15 +164,63 @@ else if (args.trapMode !== "allow") {
process.exit(1);
}
-if (args.optimize)
- module.optimize();
+var optimizeLevel = 0;
+var shrinkLevel = 0;
+var debugInfo = !args.noDebug;
+var runPasses = [];
+if (args["O"]) {
+ if (typeof args["O"] === "number")
+ optimizeLevel = args["O"];
+ else if (args["O"] === true) {
+ optimizeLevel = 2;
+ shrinkLevel = 1;
+ } else if (args["0"])
+ optimizeLevel = 0;
+ else if (args["1"])
+ optimizeLevel = 1;
+ else if (args["2"])
+ optimizeLevel = 2;
+ else if (args["3"])
+ optimizeLevel = 3;
+ else
+ optimizeLevel = 2;
+}
+if (args["s"])
+ shrinkLevel = 1;
+else if (args["z"])
+ shrinkLevel = 2;
+
+// Check explicit levels
+if (typeof args.optimizeLevel === "number")
+ optimizeLevel = args.optimizeLevel;
+if (typeof args.shrinkLevel === "number")
+ shrinkLevel = args.shrinkLevel;
+
+// Workaround for inlining not being performed (42.0.0)
+if ((optimizeLevel >= 2 || shrinkLevel >= 2) && !debugInfo)
+ runPasses = [ "inlining", "inlining-optimizing" ];
+
+// Check additional passes
if (args.runPasses) {
if (typeof args.runPasses === "string")
args.runPasses = args.runPasses.split(",");
- module.runPasses(args.runPasses.map(pass => pass.trim()));
+ if (args.runPasses.length)
+ args.runPasses.forEach(pass => {
+ if (runPasses.indexOf(pass) < 0)
+ runPasses.push(pass);
+ });
}
+module.setOptimizeLevel(optimizeLevel);
+module.setShrinkLevel(shrinkLevel);
+module.setDebugInfo(debugInfo);
+
+if (optimizeLevel || shrinkLevel)
+ module.optimize();
+if (runPasses.length)
+ module.runPasses(runPasses.map(pass => pass.trim()));
+
var hasOutput = false;
if (args.outFile != null) {
diff --git a/bin/asc.json b/bin/asc.json
index b165abfe..236c1f5c 100644
--- a/bin/asc.json
+++ b/bin/asc.json
@@ -10,10 +10,27 @@
"aliases": [ "h" ]
},
"optimize": {
- "desc": "Optimizes the module.",
- "type": "boolean",
+ "desc": [
+ "Optimizes the module. Also accepts the optimize level:",
+ " -O Equivalent to -O2s",
+ " -O0 Runs no optimization passes",
+ " -O1 Runs fast optimization passes",
+ " -O2 Runs default optimization passes",
+ " -O3 Runs all optimization passes",
+ " -O2s Specifies optimize level 2 with shrink level 1",
+ " -O3z etc."
+ ],
+ "type": "number",
"aliases": [ "O" ]
},
+ "optimizeLevel": {
+ "desc": "How much to focus on optimizing code.",
+ "type": "number"
+ },
+ "shrinkLevel": {
+ "desc": "How much to focus on shrinking code size.",
+ "type": "number"
+ },
"validate": {
"desc": "Validates the module.",
"type": "boolean",
@@ -43,6 +60,10 @@
"desc": "Disables tree-shaking.",
"type": "boolean"
},
+ "noDebug": {
+ "desc": "Disables debug information in binaries.",
+ "type": "boolean"
+ },
"noAssert": {
"desc": "Disables assertions.",
"type": "boolean"
diff --git a/examples/tlsf/package.json b/examples/tlsf/package.json
index cea56016..eab049eb 100644
--- a/examples/tlsf/package.json
+++ b/examples/tlsf/package.json
@@ -5,7 +5,7 @@
"scripts": {
"build": "npm run build:untouched && npm run build:optimized",
"build:untouched": "asc assembly/tlsf.ts -t tlsf.untouched.wast -b tlsf.untouched.wasm --validate",
- "build:optimized": "asc -O assembly/tlsf.ts -b tlsf.optimized.wasm -t tlsf.optimized.wast --validate --noAssert --runPasses inlining",
+ "build:optimized": "asc -O3 assembly/tlsf.ts -b tlsf.optimized.wasm -t tlsf.optimized.wast --validate --noDebug --noAssert",
"test": "node tests"
}
}
diff --git a/examples/ugc/assembly/ugc.ts b/examples/ugc/assembly/ugc.ts
index 90696948..ee4ed065 100644
--- a/examples/ugc/assembly/ugc.ts
+++ b/examples/ugc/assembly/ugc.ts
@@ -20,6 +20,8 @@ class ObjectHeader {
///////////////////////////////// Fields ////////////////////////////////////
+ // the next and prev pointer with tags in the least significant two bits that
+ // would otherwise be zero (blocks are guaranteed to be aligned to 4/8 bytes)
tagged_next: usize;
tagged_prev: usize;
@@ -173,13 +175,13 @@ class Control {
gc_scan_fn(this, obj);
} else {
gc_scan_fn(this, null);
- obj = this.iterator.next;
+ obj = this.iterator.next; // already strips tags, see *
if (obj == this.to) {
var from = this.from;
this.from = this.to;
this.to = from;
this.white = white ^ 1;
- this.iterator = from.next;
+ this.iterator = changetype(from.tagged_next); // *
this.state = SWEEP;
}
}
@@ -233,10 +235,10 @@ class Control {
}
}
+// TODO: should happen dynamically so it DCE's if all objects are unmanaged
var GC = Control.create(HEAP_BASE);
-var GC_BASE = HEAP_BASE + Control.SIZE;
-
-GC.register(changetype(GC_BASE));
+// var someObject = allocate_memory(64);
+// GC.register(changetype(someObject));
// Exported interface
@@ -259,7 +261,7 @@ export function gc_collect(): void {
}
// TODO: these functions must be generated by the compiler and combined by
-// any potential linker. They live here for now to document their structure.
+// a potential linker. They live here for now to document their structure.
function gc_scan_fn(control: Control, header: ObjectHeader | null): void {
if (!header) {
diff --git a/examples/ugc/package.json b/examples/ugc/package.json
index 138aef2a..a48ce201 100644
--- a/examples/ugc/package.json
+++ b/examples/ugc/package.json
@@ -5,7 +5,7 @@
"scripts": {
"build": "npm run build:untouched && npm run build:optimized",
"build:untouched": "asc assembly/ugc.ts -t ugc.untouched.wast -b ugc.untouched.wasm --validate",
- "build:optimized": "asc -O assembly/ugc.ts -b ugc.optimized.wasm -t ugc.optimized.wast --validate --noAssert --runPasses inlining",
+ "build:optimized": "asc -O3 assembly/ugc.ts -b ugc.optimized.wasm -t ugc.optimized.wast --validate --noDebug --noAssert",
"test": "node tests"
}
}
diff --git a/package-lock.json b/package-lock.json
index ff41be5a..923af15a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -274,9 +274,9 @@
"dev": true
},
"binaryen": {
- "version": "40.0.0-nightly.20171229",
- "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-40.0.0-nightly.20171229.tgz",
- "integrity": "sha512-P9VXMphJKRZbdr0AAmkpgRPGVWbnDmcqt8NPuZ+W0eSeC1igGDLdreJteCdtHA7Z+qRQ4BWqtmKPZEJKRZk47w=="
+ "version": "42.0.0",
+ "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-42.0.0.tgz",
+ "integrity": "sha512-1JkYPfxkkjkTrG1QekDeMyNdwbA/RIvlkpio+BJ41po9X6d7qZnlQHM/CNVhgXCtmGzlw2hbkAyYxEfnE001vw=="
},
"bn.js": {
"version": "4.11.8",
diff --git a/package.json b/package.json
index da6b76ad..7e5ba40c 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"url": "https://github.com/AssemblyScript/assemblyscript/issues"
},
"dependencies": {
- "binaryen": "40.0.0-nightly.20171229",
+ "binaryen": "42.0.0",
"glob": "^7.1.2",
"minimist": "^1.2.0"
},
diff --git a/src/module.ts b/src/module.ts
index 4626c1d8..8e537aad 100644
--- a/src/module.ts
+++ b/src/module.ts
@@ -727,9 +727,19 @@ export class Module {
_BinaryenSetStart(this.ref, func);
}
+ setOptimizeLevel(level: i32 = 2): void {
+ _BinaryenSetOptimizeLevel(level);
+ }
+
+ setShrinkLevel(level: i32 = 1): void {
+ _BinaryenSetShrinkLevel(level);
+ }
+
+ setDebugInfo(on: bool = false): void {
+ _BinaryenSetDebugInfo(on);
+ }
+
optimize(func: FunctionRef = 0): void {
- // see: https://github.com/WebAssembly/binaryen/issues/1331#issuecomment-350328175
- // this.runPasses([ "flatten", "ssa" ], func);
if (func) {
_BinaryenFunctionOptimize(func, this.ref);
} else {