Skip to content

Commit 0484a6b

Browse files
authored
Implement reference counting (#592)
1 parent 3ed76a9 commit 0484a6b

File tree

601 files changed

+258482
-142968
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

601 files changed

+258482
-142968
lines changed

.travis.yml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,15 @@ notifications:
33
email: false
44
before_install: npm config set progress=false && npm i -g npm@latest --no-audit
55
install: npm ci --no-audit
6-
cache:
7-
directories:
8-
- node_modules
96
jobs:
107
include:
118
- node_js: lts/*
129
script:
13-
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then ./scripts/check-pr.sh; fi
10+
- if [ "$TRAVIS_PULL_REQUEST" != "false" ] && [ "$TRAVIS_PULL_REQUEST_BRANCH" != "dev" ]; then ./scripts/check-pr.sh; fi
1411
- npm run all
1512
- if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
16-
cd $TRAVIS_BUILD_DIR/tests/allocators/arena && npm run build && cd .. && npm test arena &&
17-
cd $TRAVIS_BUILD_DIR/tests/allocators/buddy && npm run build && cd .. && npm test buddy &&
18-
cd $TRAVIS_BUILD_DIR/tests/allocators/tlsf && npm run build && cd .. && npm test tlsf;
13+
cd $TRAVIS_BUILD_DIR/tests/allocators/rt-full && npm run build && cd .. && npm test rt-full &&
14+
cd $TRAVIS_BUILD_DIR/tests/allocators/rt-stub && npm run build && cd .. && npm test rt-stub;
1915
fi
2016
env: Runs the tests on node.js LTS, also tests allocators
2117
- node_js: node
@@ -24,7 +20,7 @@ jobs:
2420
env: Runs the tests on node.js stable
2521
- node_js: node
2622
script:
27-
- npm run clean && npm run test:compiler
23+
- npm run clean && npm run test:compiler rt/flags threads
2824
env:
2925
- Runs experimental tests on node.js v8-canary using
3026
- ASC_FEATURES="simd,threads"

README.md

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
[![Build Status](https://travis-ci.org/AssemblyScript/assemblyscript.svg?branch=master)](https://travis-ci.org/AssemblyScript/assemblyscript)
55

6-
**AssemblyScript** compiles strictly typed [TypeScript](http://www.typescriptlang.org) (basically JavaScript with types) to [WebAssembly](http://webassembly.org) using [Binaryen](https://github.com/WebAssembly/binaryen). It generates lean and mean WebAssembly modules while being just an `npm install` away.
6+
**AssemblyScript** compiles a strict subset of [TypeScript](http://www.typescriptlang.org) (basically JavaScript with types) to [WebAssembly](http://webassembly.org) using [Binaryen](https://github.com/WebAssembly/binaryen). It generates lean and mean WebAssembly modules while being just an `npm install` away.
77

8-
Try it out in [WebAssembly Studio](https://webassembly.studio)!
8+
Check out the [documentation](https://docs.assemblyscript.org) or try it out in [WebAssembly Studio](https://webassembly.studio)!
99

1010
---
1111

@@ -43,60 +43,20 @@ Motivation
4343
4444
> I do think [compiling TypeScript into WASM] is tremendously useful. It allows JavaScript developers to create WASM modules without having to learn C. – Colin Eberhardt, [Exploring different approaches to building WebAssembly modules](http://blog.scottlogic.com/2017/10/17/wasm-mandelbrot.html) (Oct 17, 2017)
4545
46-
Getting started
47-
---------------
46+
Instructions
47+
------------
4848

49-
All the details are provided in the [AssemblyScript wiki](https://github.com/AssemblyScript/assemblyscript/wiki) - make sure to pay it a visit. With that being said, the easiest way to get started with AssemblyScript is to point npm at the GitHub repository (for now)
50-
51-
```
52-
$> npm install --save-dev AssemblyScript/assemblyscript
53-
```
54-
55-
followed by [scaffolding](https://github.com/AssemblyScript/assemblyscript/wiki/Using-the-CLI#scaffolding-with-asinit) a new project including the necessary configuration files, for example in the current directory:
56-
57-
```
58-
$> npx asinit .
59-
```
60-
61-
Once the project is set up, it's just a matter of using your existing [TypeScript tooling](https://code.visualstudio.com) while coding, and [using the CLI](https://github.com/AssemblyScript/assemblyscript/wiki/Using-the-CLI) to build to WebAssembly, either manually, or using (and maybe modifying) the generated build task in the generated `package.json`:
62-
63-
```
64-
$> npm run asbuild
65-
```
66-
67-
The CLI API can also [be used programmatically](./cli).
68-
69-
If you rather prefer an installation suitable for development, pretty much the same can be achieved by cloning the GitHub repository instead:
49+
For general usage instructions, please refer to the [documentation](https://docs.assemblyscript.org) instead. The following sets up a *development environment* of the compiler, for example if you plan to make a pull request:
7050

7151
```
7252
$> git clone https://github.com/AssemblyScript/assemblyscript.git
7353
$> cd assemblyscript
7454
$> npm install
7555
$> npm link
56+
$> npm clean
7657
```
7758

78-
**Note** that a fresh clone of the compiler will use the distribution files in `dist/`, but it can also run [the sources](./src) directly through ts-node after an `npm run clean`, which is useful in development. This condition can also be checked by running `asc -v` (it is running the sources if it states `-dev`).
79-
80-
Examples
81-
--------
82-
83-
* **[Conway's Game of Life](./examples/game-of-life)** [ [demo](https://assemblyscript.github.io/assemblyscript/examples/game-of-life) | [fiddle](https://webassembly.studio/?f=gvuw4enb3qk) ]<br />
84-
Continuously updates the cellular automaton and visualizes its state on a canvas.
85-
86-
* **[Mandelbrot Set](./examples/mandelbrot)** [ [demo](https://assemblyscript.github.io/assemblyscript/examples/mandelbrot) | [fiddle](https://webassembly.studio/?f=m6hbiw9wyq) ]<br />
87-
Renders the Mandelbrot set to a canvas.
88-
89-
* **[i64 polyfill](./examples/i64-polyfill)**<br />
90-
Exposes WebAssembly's i64 operations to JavaScript using 32-bit integers (low and high bits).
91-
92-
* **[PSON decoder](./examples/pson)**<br />
93-
A simple decoder for the PSON binary format.
94-
95-
* **[WASM parser](./lib/parse)**<br />
96-
A WebAssembly binary parser in WebAssembly.
97-
98-
* **[N-body system](./examples/n-body)** [ [demo](https://assemblyscript.github.io/assemblyscript/examples/n-body) ]<br />
99-
An implementation of the N-body system from the [Computer Language Benchmarks Game](https://benchmarksgame-team.pages.debian.net/benchmarksgame/).
59+
Note that a fresh clone of the compiler will use the distribution files in `dist/`, but after an `npm clean` it will run [the sources](./src) directly through ts-node, which is useful in development. This condition can also be checked by running `asc -v` (it is running the sources if it states `-dev`). Also please see our [contribution guidelines](./CONTRIBUTING.md) before making your first pull request.
10060

10161
Building
10262
--------

cli/asc.js

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const optionsUtil = require("./util/options");
2222
const mkdirp = require("./util/mkdirp");
2323
const EOL = process.platform === "win32" ? "\r\n" : "\n";
2424

25+
// global.Binaryen = require("../lib/binaryen");
26+
2527
// Emscripten adds an `uncaughtException` listener to Binaryen that results in an additional
2628
// useless code fragment on top of an actual error. suppress this:
2729
if (process.removeAllListeners) process.removeAllListeners("uncaughtException");
@@ -68,7 +70,7 @@ exports.sourceMapRoot = "assemblyscript:///";
6870
exports.libraryPrefix = assemblyscript.LIBRARY_PREFIX;
6971

7072
/** Default Binaryen optimization level. */
71-
exports.defaultOptimizeLevel = 2;
73+
exports.defaultOptimizeLevel = 3;
7274

7375
/** Default Binaryen shrink level. */
7476
exports.defaultShrinkLevel = 1;
@@ -228,30 +230,18 @@ exports.main = function main(argv, options, callback) {
228230
var parser = null;
229231

230232
// Include library files
231-
if (!args.noLib) {
232-
Object.keys(exports.libraryFiles).forEach(libPath => {
233-
if (libPath.indexOf("/") >= 0) return; // in sub-directory: imported on demand
234-
stats.parseCount++;
235-
stats.parseTime += measure(() => {
236-
parser = assemblyscript.parseFile(
237-
exports.libraryFiles[libPath],
238-
exports.libraryPrefix + libPath + ".ts",
239-
false,
240-
parser
241-
);
242-
});
243-
});
244-
} else { // always include builtins
233+
Object.keys(exports.libraryFiles).forEach(libPath => {
234+
if (libPath.indexOf("/") >= 0) return; // in sub-directory: imported on demand
245235
stats.parseCount++;
246236
stats.parseTime += measure(() => {
247237
parser = assemblyscript.parseFile(
248-
exports.libraryFiles["builtins"],
249-
exports.libraryPrefix + "builtins.ts",
238+
exports.libraryFiles[libPath],
239+
exports.libraryPrefix + libPath + ".ts",
250240
false,
251241
parser
252242
);
253243
});
254-
}
244+
});
255245
const customLibDirs = [];
256246
if (args.lib) {
257247
let lib = args.lib;
@@ -287,6 +277,7 @@ exports.main = function main(argv, options, callback) {
287277
function parseBacklog() {
288278
var sourcePath, sourceText;
289279
while ((sourcePath = parser.nextFile()) != null) {
280+
sourceText = null;
290281

291282
// Load library file if explicitly requested
292283
if (sourcePath.startsWith(exports.libraryPrefix)) {
@@ -335,12 +326,12 @@ exports.main = function main(argv, options, callback) {
335326
} else {
336327
for (let i = 0, k = customLibDirs.length; i < k; ++i) {
337328
const dir = customLibDirs[i];
338-
sourceText = readFile(plainName + ".ts", customLibDirs[i]);
329+
sourceText = readFile(plainName + ".ts", dir);
339330
if (sourceText !== null) {
340331
sourcePath = exports.libraryPrefix + plainName + ".ts";
341332
break;
342333
} else {
343-
sourceText = readFile(indexName + ".ts", customLibDirs[i]);
334+
sourceText = readFile(indexName + ".ts", dir);
344335
if (sourceText !== null) {
345336
sourcePath = exports.libraryPrefix + indexName + ".ts";
346337
break;
@@ -364,6 +355,26 @@ exports.main = function main(argv, options, callback) {
364355
}
365356
}
366357

358+
// Include runtime template before entry files so its setup runs first
359+
{
360+
let runtimeName = String(args.runtime);
361+
let runtimePath = "rt/index-" + runtimeName;
362+
let runtimeText = exports.libraryFiles[runtimePath];
363+
if (runtimeText == null) {
364+
runtimePath = runtimeName;
365+
runtimeText = readFile(runtimePath + ".ts", baseDir);
366+
if (runtimeText == null) {
367+
return callback(Error("Runtime '" + runtimeName + "' not found."));
368+
}
369+
} else {
370+
runtimePath = "~lib/" + runtimePath;
371+
}
372+
stats.parseCount++;
373+
stats.parseTime += measure(() => {
374+
parser = assemblyscript.parseFile(runtimeText, runtimePath, true, parser);
375+
});
376+
}
377+
367378
// Include entry files
368379
for (let i = 0, k = argv.length; i < k; ++i) {
369380
const filename = argv[i];
@@ -387,11 +398,18 @@ exports.main = function main(argv, options, callback) {
387398
stats.parseTime += measure(() => {
388399
parser = assemblyscript.parseFile(sourceText, sourcePath, true, parser);
389400
});
401+
}
402+
403+
// Parse entry files
404+
{
390405
let code = parseBacklog();
391406
if (code) return code;
392407
}
393408

409+
// Call afterParse transform hook
394410
applyTransform("afterParse", parser);
411+
412+
// Parse additional files, if any
395413
{
396414
let code = parseBacklog();
397415
if (code) return code;
@@ -423,17 +441,16 @@ exports.main = function main(argv, options, callback) {
423441
assemblyscript.setImportMemory(compilerOptions, args.importMemory);
424442
assemblyscript.setSharedMemory(compilerOptions, args.sharedMemory);
425443
assemblyscript.setImportTable(compilerOptions, args.importTable);
444+
assemblyscript.setExplicitStart(compilerOptions, args.explicitStart);
426445
assemblyscript.setMemoryBase(compilerOptions, args.memoryBase >>> 0);
427446
assemblyscript.setSourceMap(compilerOptions, args.sourceMap != null);
428447
assemblyscript.setOptimizeLevelHints(compilerOptions, optimizeLevel, shrinkLevel);
429448

430-
if (!args.noLib) {
431-
// Initialize default aliases
432-
assemblyscript.setGlobalAlias(compilerOptions, "Math", "NativeMath");
433-
assemblyscript.setGlobalAlias(compilerOptions, "Mathf", "NativeMathf");
434-
assemblyscript.setGlobalAlias(compilerOptions, "abort", "~lib/env/abort");
435-
assemblyscript.setGlobalAlias(compilerOptions, "trace", "~lib/env/trace");
436-
}
449+
// Initialize default aliases
450+
assemblyscript.setGlobalAlias(compilerOptions, "Math", "NativeMath");
451+
assemblyscript.setGlobalAlias(compilerOptions, "Mathf", "NativeMathf");
452+
assemblyscript.setGlobalAlias(compilerOptions, "abort", "~lib/builtins/abort");
453+
assemblyscript.setGlobalAlias(compilerOptions, "trace", "~lib/builtins/trace");
437454

438455
// Add or override aliases if specified
439456
if (args.use) {
@@ -463,15 +480,13 @@ exports.main = function main(argv, options, callback) {
463480

464481
var module;
465482
stats.compileCount++;
466-
(() => {
467-
try {
468-
stats.compileTime += measure(() => {
469-
module = assemblyscript.compileProgram(program, compilerOptions);
470-
});
471-
} catch (e) {
472-
return callback(e);
473-
}
474-
})();
483+
try {
484+
stats.compileTime += measure(() => {
485+
module = assemblyscript.compileProgram(program, compilerOptions);
486+
});
487+
} catch (e) {
488+
return callback(e);
489+
}
475490
if (checkDiagnostics(parser, stderr)) {
476491
if (module) module.dispose();
477492
return callback(Error("Compile error"));
@@ -697,6 +712,9 @@ exports.main = function main(argv, options, callback) {
697712
if (args.measure) {
698713
printStats(stats, stderr);
699714
}
715+
if (args.printrtti) {
716+
printRTTI(program, stderr);
717+
}
700718
return callback(null);
701719

702720
function readFileNode(filename, baseDir) {
@@ -833,6 +851,15 @@ function printStats(stats, output) {
833851

834852
exports.printStats = printStats;
835853

854+
/** Prints runtime type information. */
855+
function printRTTI(program, output) {
856+
if (!output) output = process.stderr;
857+
output.write("# Runtime type information (RTTI)\n");
858+
output.write(assemblyscript.buildRTTI(program));
859+
}
860+
861+
exports.printRTTI = printRTTI;
862+
836863
var allocBuffer = typeof global !== "undefined" && global.Buffer
837864
? global.Buffer.allocUnsafe || function(len) { return new global.Buffer(len); }
838865
: function(len) { return new Uint8Array(len) };

cli/asc.json

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"description": [
1414
"Optimizes the module. Also has the usual shorthands:",
1515
"",
16-
" -O Uses defaults. Equivalent to -O2s",
16+
" -O Uses defaults. Equivalent to -O3s",
1717
" -O0 Equivalent to --optimizeLevel 0",
1818
" -O1 Equivalent to --optimizeLevel 1",
1919
" -O2 Equivalent to --optimizeLevel 2",
@@ -81,6 +81,19 @@
8181
],
8282
"type": "s"
8383
},
84+
"runtime": {
85+
"description": [
86+
"Specifies the runtime implementation to include in the program.",
87+
"",
88+
" full Default runtime based on TLSF and reference counting.",
89+
" half Same as 'full', but not exported to the host.",
90+
" stub Minimal stub implementation without free/GC support.",
91+
" none Same as 'stub', but not exported to the host.",
92+
""
93+
],
94+
"type": "s",
95+
"default": "full"
96+
},
8497
"debug": {
8598
"description": "Enables debug information in emitted binaries.",
8699
"type": "b",
@@ -116,8 +129,8 @@
116129
"type": "b",
117130
"default": false
118131
},
119-
"noLib": {
120-
"description": "Does not include the shipped standard library.",
132+
"explicitStart": {
133+
"description": "Exports an explicit start function to be called manually.",
121134
"type": "b",
122135
"default": false
123136
},
@@ -177,6 +190,11 @@
177190
"type": "b",
178191
"default": false
179192
},
193+
"printrtti": {
194+
"description": "Prints the module's runtime type information to stderr.",
195+
"type": "b",
196+
"default": false
197+
},
180198
"noColors": {
181199
"description": "Disables terminal colors.",
182200
"type": "b",

dist/asc.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/asc.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)