├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── benchmarks ├── README ├── access-nbody.ljs ├── access-nbody.orig.js └── linked-list.ljs ├── bin └── ljc ├── docs ├── CNAME ├── css │ └── screen.css ├── demo.html ├── images │ ├── arrays.png │ ├── background.png │ ├── banding.png │ ├── button_bg.png │ ├── button_bg_dark.gif │ ├── button_bg_green.gif │ ├── fork.png │ ├── heap.png │ ├── mozilla.png │ └── screenshadow.png ├── index.html ├── lljs └── vendor │ ├── cm │ ├── lib │ │ ├── codemirror.css │ │ ├── codemirror.js │ │ └── util │ │ │ ├── closetag.js │ │ │ ├── dialog.css │ │ │ ├── dialog.js │ │ │ ├── foldcode.js │ │ │ ├── formatting.js │ │ │ ├── javascript-hint.js │ │ │ ├── loadmode.js │ │ │ ├── match-highlighter.js │ │ │ ├── overlay.js │ │ │ ├── runmode.js │ │ │ ├── search.js │ │ │ ├── searchcursor.js │ │ │ ├── simple-hint.css │ │ │ └── simple-hint.js │ ├── mode │ │ └── javascript │ │ │ ├── index.html │ │ │ └── javascript.js │ └── theme │ │ ├── ambiance.css │ │ ├── blackboard.css │ │ ├── cobalt.css │ │ ├── eclipse.css │ │ ├── elegant.css │ │ ├── lesser-dark.css │ │ ├── monokai.css │ │ ├── neat.css │ │ ├── night.css │ │ ├── rubyblue.css │ │ └── xq-dark.css │ └── jquery-1.7.2.min.js ├── src ├── compiler.js ├── escodegen.js ├── esprima.js ├── estransform.js ├── ljc.js ├── memcheck.js ├── memcheck.ljs ├── memory.js ├── memory.ljs ├── modules.js ├── pool.js ├── pool.ljs ├── scope.js ├── template │ ├── footer.js │ └── header.js ├── tests │ ├── structs-0.ljs │ └── test-memcheck.ljs ├── types.js └── util.js └── test ├── arrays-stack.ljs ├── arrays.ljs ├── asm ├── bench.c ├── bench.js ├── bench.ljs ├── bench2.c ├── bench2.js ├── bench2.ljs ├── bridge.js ├── functions.js ├── functions.ljs ├── memory.js ├── memory.ljs ├── primitives.js ├── primitives.ljs ├── types.js └── types.ljs ├── matrix.ljs ├── structs-members.ljs ├── structs-static-members.ljs ├── structs.ljs └── types.ljs /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .#* 3 | build 4 | .DS_Store 5 | .asm.output 6 | a.out -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Mozilla Foundation 2 | 3 | Contributors: Michael Bebenita 4 | Shu-yu Guo 5 | Stephen Crane 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LJC = bin/ljc 2 | ND_FLAGS = -0 3 | SM_FLAGS = -0 -l 4 | 5 | srcdir = src 6 | testdir = src/tests 7 | benchdir = benchmarks 8 | 9 | build_node = build/node 10 | build_sm = build/sm 11 | 12 | js_files = memory.js memcheck.js test-memcheck.js \ 13 | access-nbody.js access-nbody-memcheck.js \ 14 | linked-list.js linked-list-memcheck.js 15 | 16 | asmtestfiles = $(addprefix test/asm/, primitives.js functions.js types.js memory.js) 17 | 18 | mainfiles = $(addprefix $(srcdir)/, memory.js memcheck.js) 19 | nodefiles := $(addprefix $(build_node)/, $(js_files)) 20 | smfiles := $(addprefix $(build_sm)/, $(js_files)) 21 | 22 | V8_ENGINE ?= node 23 | SPIDERMONKEY_ENGINE ?= ~/projects/jsshell/js 24 | SPIDERMONKEY_ENGINE_NOASM ?= ~/projects/jsshell/js 25 | 26 | 27 | .PHONY: all test clean node sm bench main 28 | 29 | all: main node sm test bench 30 | 31 | test: node sm 32 | @echo "======================" 33 | @echo "Running node tests..." 34 | (export NODE_PATH="$(build_node):$$NODE_PATH" && $(V8_ENGINE) --harmony_proxies $(build_node)/test-memcheck.js) 35 | @echo "======================" 36 | @echo "Running spidermonkey tests..." 37 | (cd $(build_sm) && $(SPIDERMONKEY_ENGINE) -n -m test-memcheck.js) 38 | 39 | bench: node sm 40 | @echo "======================" 41 | @echo "Running node benchmarks..." 42 | @echo "== nbody ==" 43 | (export NODE_PATH="$(build_node):$$NODE_PATH" && $(V8_ENGINE) --harmony_proxies $(build_node)/access-nbody.js) 44 | @echo "\n== nbody (memcheck) ==" 45 | (export NODE_PATH="$(build_node):$$NODE_PATH" && $(V8_ENGINE) --harmony_proxies $(build_node)/access-nbody-memcheck.js) 46 | @echo "\n== linked list ==" 47 | (export NODE_PATH="$(build_node):$$NODE_PATH" && $(V8_ENGINE) --harmony_proxies $(build_node)/linked-list.js) 48 | @echo "\n== linked list (memcheck) ==" 49 | (export NODE_PATH="$(build_node):$$NODE_PATH" && $(V8_ENGINE) --harmony_proxies $(build_node)/linked-list-memcheck.js) 50 | @echo "======================" 51 | @echo "Running spidermonkey benchmarks..." 52 | @echo "== nbody ==" 53 | (cd $(build_sm) && $(SPIDERMONKEY_ENGINE) -n -m access-nbody.js) 54 | @echo "\n== nbody (memcheck) ==" 55 | (cd $(build_sm) && $(SPIDERMONKEY_ENGINE) -n -m access-nbody-memcheck.js) 56 | @echo "\n== linked list ==" 57 | (cd $(build_sm) && $(SPIDERMONKEY_ENGINE) -n -m linked-list.js) 58 | @echo "\n== linked list (memcheck) ==" 59 | (cd $(build_sm) && $(SPIDERMONKEY_ENGINE) -n -m linked-list-memcheck.js) 60 | 61 | main: $(mainfiles) 62 | node: $(nodefiles) 63 | sm: $(smfiles) 64 | 65 | asmtest: $(asmtestfiles) $(addprefix asmtest_, $(asmtestfiles)) 66 | asmbench: test/asm/bench2.js 67 | @echo "======================" 68 | @echo "Using v8..." 69 | $(V8_ENGINE) $< 70 | @echo "Using spidermonkey..." 71 | $(SPIDERMONKEY_ENGINE_NOASM) $< 72 | @echo "Using spidermonkey+asm.js..." 73 | $(SPIDERMONKEY_ENGINE) $< 74 | 75 | asmtest_test/asm/%.js: test/asm/%.js 76 | @echo "======================" 77 | @echo "Testing $<..." 78 | $(V8_ENGINE) $< 79 | @echo "Spidermonkey:" 80 | $(SPIDERMONKEY_ENGINE) $< 2>.asm.output 81 | @cat .asm.output 82 | @cat .asm.output | grep -i 'success' >/dev/null 83 | @rm .asm.output 84 | 85 | asmclean: 86 | rm $(asmtestfiles) 87 | 88 | test/asm/%.js: test/asm/%.ljs 89 | $(LJC) $(ND_FLAGS) -a -o $@ $< 90 | 91 | # main 92 | $(srcdir)/memory.js: $(srcdir)/memory.ljs 93 | $(LJC) $(ND_FLAGS) -o $@ $< 94 | 95 | $(srcdir)/memcheck.js: $(srcdir)/memcheck.ljs 96 | $(LJC) $(ND_FLAGS) -o $@ $< 97 | 98 | # node 99 | $(build_node)/memory.js: $(srcdir)/memory.ljs 100 | $(LJC) $(ND_FLAGS) -o $@ $< 101 | 102 | $(build_node)/memcheck.js: $(srcdir)/memcheck.ljs 103 | $(LJC) $(ND_FLAGS) -o $@ $< 104 | 105 | $(build_node)/test-memcheck.js: $(testdir)/test-memcheck.ljs 106 | $(LJC) $(ND_FLAGS) -m -o $@ $< 107 | 108 | # benchmarks 109 | $(build_node)/access-nbody.js: $(benchdir)/access-nbody.ljs 110 | $(LJC) $(ND_FLAGS) -o $@ $< 111 | 112 | $(build_node)/linked-list.js: $(benchdir)/linked-list.ljs 113 | $(LJC) $(ND_FLAGS) -o $@ $< 114 | 115 | $(build_node)/access-nbody-memcheck.js: $(benchdir)/access-nbody.ljs 116 | $(LJC) $(ND_FLAGS) -m -o $@ $< 117 | 118 | $(build_node)/linked-list-memcheck.js: $(benchdir)/linked-list.ljs 119 | $(LJC) $(ND_FLAGS) -m -o $@ $< 120 | 121 | 122 | # spidermonkey 123 | $(build_sm)/memory.js: $(srcdir)/memory.ljs 124 | $(LJC) $(SM_FLAGS) -o $@ $< 125 | 126 | $(build_sm)/memcheck.js: $(srcdir)/memcheck.ljs 127 | $(LJC) $(SM_FLAGS) -o $@ $< 128 | 129 | $(build_sm)/test-memcheck.js: $(testdir)/test-memcheck.ljs 130 | $(LJC) $(SM_FLAGS) -m -o $@ $< 131 | 132 | # benchmarks 133 | $(build_sm)/access-nbody.js: $(benchdir)/access-nbody.ljs 134 | $(LJC) $(SM_FLAGS) -o $@ $< 135 | 136 | $(build_sm)/linked-list.js: $(benchdir)/linked-list.ljs 137 | $(LJC) $(SM_FLAGS) -o $@ $< 138 | 139 | $(build_sm)/access-nbody-memcheck.js: $(benchdir)/access-nbody.ljs 140 | $(LJC) $(SM_FLAGS) -m -o $@ $< 141 | 142 | $(build_sm)/linked-list-memcheck.js: $(benchdir)/linked-list.ljs 143 | $(LJC) $(SM_FLAGS) -m -o $@ $< 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LLJS 2 | ==== 3 | 4 | LLJS is a typed dialect of JavaScript that offers a 5 | C-like type system with manual memory management. It compiles to JavaScript 6 | and lets you write memory-efficient and GC pause-free code less painfully, in 7 | short, LLJS is the bastard child of JavaScript and C. LLJS is early research 8 | prototype work, so don't expect anything rock solid just yet. The research 9 | goal here is to explore low-level statically typed features in a high-level 10 | dynamically typed language. Think of it as inline assembly in C, or the 11 | unsafe keyword in C#. It's not pretty, but it gets the job done. 12 | 13 | [Try It Online](http://lljs.org) 14 | 15 | Usage 16 | ===== 17 | 18 | For users of node.js, `bin/ljc` is provided. 19 | 20 | For users of SpiderMonkey `js` shell, the compiler can be invoked with: 21 | 22 | $ js ljc.js 23 | 24 | in the src/ directory. 25 | 26 | asm.js 27 | ====== 28 | 29 | This is an experimental version of LLJS that compiles to asm.js. Not everything is working yet, and dynamic allocation isn't implemented yet, but it will be soon. See [this blog post](http://jlongster.com/Compiling-LLJS-to-asm.js,-Now-Available-). 30 | 31 | To run the asm.js tests, run `make asmtest`. To run the benchmark, run `make asmbench`. You can see the working examples in the `test/asm` folder; 32 | 33 | You might need to define the SPIDERMONKEY_ENGINE and V8_ENGINE environment variables to run the tests (they default to `js` and `node` respectively). You will also need to define SPIDERMONKEY_ENGINE_NOASM to point to a version of SpiderMonkey without asm.js if you want to run the benchmarks. 34 | 35 | Memcheck 36 | ======== 37 | 38 | If you would like to compile with support for [memory checking](http://disnetdev.com/blog/2012/07/18/memory-checking-in-low-level-javascript/) (detects 39 | leaks, accesses of unallocated and undefined memory locations, and 40 | double frees) then compile with the -m flag: 41 | 42 | $ bin/ljc -m -o myscript.js myscript.ljs 43 | 44 | And add the following code to the end of your program run to report 45 | any memory errors: 46 | 47 | let m = require('memory'); 48 | // for SpiderMonkey do 49 | // let m = load('memory.js') 50 | console.log(m.memcheck.report()); 51 | 52 | The memory checker uses Proxies so if you use node.js you need to 53 | enable it with: 54 | 55 | $ node --harmony-proxies myscript.js 56 | 57 | Testing 58 | ======= 59 | 60 | To run the tests install the [Mocha](http://visionmedia.github.com/mocha/) module then run: 61 | 62 | export NODE_PATH=src/ 63 | mocha --compilers ljs:ljc 64 | 65 | from the root LLJS directory. -------------------------------------------------------------------------------- /benchmarks/README: -------------------------------------------------------------------------------- 1 | Running Benchmarks 2 | ------------------ 3 | 4 | Under SpiderMonkey: 5 | 6 | $ cp ../src/memory.js . 7 | $ js -n -m ../src/ljc.js -l .ljs 8 | $ js -n -m .js 9 | 10 | Under Node: 11 | 12 | $ export NODE_PATH="../src:$NODE_PATH" 13 | $ ../bin/ljc .ljs 14 | $ node .js 15 | -------------------------------------------------------------------------------- /benchmarks/access-nbody.ljs: -------------------------------------------------------------------------------- 1 | /* The Great Computer Language Shootout 2 | http://shootout.alioth.debian.org/ 3 | contributed by Isaac Gouy */ 4 | 5 | typedef byte *malloc_ty(uint); 6 | let malloc_ty malloc; 7 | if (typeof require !== "undefined") { 8 | malloc = (malloc_ty)(require('memory').malloc); 9 | } else { 10 | extern memory; 11 | malloc = (malloc_ty)(memory.malloc); 12 | } 13 | 14 | struct Body { 15 | double x, y, z, vx, vy, vz, mass; 16 | }; 17 | 18 | const double PI = 3.141592653589793; 19 | const double SOLAR_MASS = 4 * PI * PI; 20 | const double DAYS_PER_YEAR = 365.24; 21 | 22 | function setBody(Body *b, 23 | double x, double y, double z, 24 | double vx, double vy, double vz, 25 | double mass) { 26 | b->x = x; 27 | b->y = y; 28 | b->z = z; 29 | b->vx = vx; 30 | b->vy = vy; 31 | b->vz = vz; 32 | b->mass = mass; 33 | } 34 | 35 | function setJupiter(Body *b) { 36 | setBody(b, 37 | 4.84143144246472090e+00, 38 | -1.16032004402742839e+00, 39 | -1.03622044471123109e-01, 40 | 1.66007664274403694e-03 * DAYS_PER_YEAR, 41 | 7.69901118419740425e-03 * DAYS_PER_YEAR, 42 | -6.90460016972063023e-05 * DAYS_PER_YEAR, 43 | 9.54791938424326609e-04 * SOLAR_MASS); 44 | } 45 | 46 | function setSaturn(Body *b) { 47 | setBody(b, 48 | 8.34336671824457987e+00, 49 | 4.12479856412430479e+00, 50 | -4.03523417114321381e-01, 51 | -2.76742510726862411e-03 * DAYS_PER_YEAR, 52 | 4.99852801234917238e-03 * DAYS_PER_YEAR, 53 | 2.30417297573763929e-05 * DAYS_PER_YEAR, 54 | 2.85885980666130812e-04 * SOLAR_MASS); 55 | } 56 | 57 | function setUranus(Body *b) { 58 | setBody(b, 59 | 1.28943695621391310e+01, 60 | -1.51111514016986312e+01, 61 | -2.23307578892655734e-01, 62 | 2.96460137564761618e-03 * DAYS_PER_YEAR, 63 | 2.37847173959480950e-03 * DAYS_PER_YEAR, 64 | -2.96589568540237556e-05 * DAYS_PER_YEAR, 65 | 4.36624404335156298e-05 * SOLAR_MASS); 66 | } 67 | 68 | function setNeptune(Body *b) { 69 | setBody(b, 70 | 1.53796971148509165e+01, 71 | -2.59193146099879641e+01, 72 | 1.79258772950371181e-01, 73 | 2.68067772490389322e-03 * DAYS_PER_YEAR, 74 | 1.62824170038242295e-03 * DAYS_PER_YEAR, 75 | -9.51592254519715870e-05 * DAYS_PER_YEAR, 76 | 5.15138902046611451e-05 * SOLAR_MASS); 77 | } 78 | 79 | function setSun(Body *b) { 80 | setBody(b, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS); 81 | } 82 | 83 | function Body *offsetMomentum(Body *b, double px, double py, double pz) { 84 | b->vx = -px / SOLAR_MASS; 85 | b->vy = -py / SOLAR_MASS; 86 | b->vz = -pz / SOLAR_MASS; 87 | return b; 88 | } 89 | 90 | const int NBODIES = 5; 91 | 92 | function NBodySystem() { 93 | let Body *bodies = (Body *)(malloc(sizeof(Body) * NBODIES)); 94 | 95 | setSun(bodies); 96 | setJupiter(bodies + 1); 97 | setSaturn(bodies + 2); 98 | setUranus(bodies + 3); 99 | setNeptune(bodies + 4); 100 | 101 | let double px = 0.0; 102 | let double py = 0.0; 103 | let double pz = 0.0; 104 | for (let int i = 0; i < NBODIES; ++i) { 105 | let Body *b = bodies + i; 106 | let double mass = b->mass; 107 | px += b->vx * mass; 108 | py += b->vy * mass; 109 | pz += b->vz * mass; 110 | } 111 | offsetMomentum(bodies, px, py, pz); 112 | 113 | this.bodies = bodies; 114 | } 115 | 116 | extern Math; 117 | 118 | NBodySystem.prototype = { 119 | advance: function advance(double dt) { 120 | let double dx, dy, dz, distance, mag; 121 | let Body *bodies = (Body *)(this->bodies); 122 | 123 | for (let int i = 0; i < NBODIES; ++i) { 124 | let Body *bi = bodies + i; 125 | for (let int j = i + 1; j < NBODIES; ++j) { 126 | let Body *bj = bodies + j; 127 | dx = bi->x - bj->x; 128 | dy = bi->y - bj->y; 129 | dz = bi->z - bj->z; 130 | distance = (double)(Math.sqrt(dx * dx + dy * dy + dz * dz)); 131 | mag = dt / (distance * distance * distance); 132 | 133 | bi->vx -= dx * bj->mass * mag; 134 | bi->vy -= dy * bj->mass * mag; 135 | bi->vz -= dz * bj->mass * mag; 136 | 137 | bj->vx += dx * bi->mass * mag; 138 | bj->vy += dy * bi->mass * mag; 139 | bj->vz += dz * bi->mass * mag; 140 | } 141 | } 142 | 143 | for (let int i = 0; i < NBODIES; ++i) { 144 | let Body *b = bodies + i; 145 | b->x += dt * b->vx; 146 | b->y += dt * b->vy; 147 | b->z += dt * b->vz; 148 | } 149 | }, 150 | 151 | energy: function double energy() { 152 | let double dx, dy, dz, distance; 153 | let double e = 0.0; 154 | let Body *bodies = (Body *)(this->bodies); 155 | 156 | for (let int i = 0; i < NBODIES; ++i) { 157 | let Body *bi = bodies + i; 158 | 159 | e += 0.5 * bi->mass * (bi->vx * bi->vx + 160 | bi->vy * bi->vy + 161 | bi->vz * bi->vz); 162 | 163 | for (let int j = i + 1; j < NBODIES; ++j) { 164 | let Body *bj = bodies + j; 165 | dx = bi->x - bj->x; 166 | dy = bi->y - bj->y; 167 | dz = bi->z - bj->z; 168 | 169 | distance = (double)(Math.sqrt(dx * dx + dy * dy + dz * dz)); 170 | 171 | e -= (bi->mass * bj->mass) / distance; 172 | } 173 | } 174 | 175 | return e; 176 | } 177 | }; 178 | 179 | extern print; 180 | if (typeof print === "undefined") { 181 | extern console; 182 | print = console.log; 183 | } 184 | 185 | function double run() { 186 | let double res; 187 | 188 | for (let int n = 3; n <= 24; n *= 2) { 189 | let bodies = new NBodySystem(); 190 | let int max = n * 100; 191 | 192 | for (let int i = 0; i < max; ++i) { 193 | bodies.advance(0.01); 194 | } 195 | res = (double)(bodies.energy()); 196 | print("" + n + "=" + res); 197 | } 198 | 199 | return res; 200 | } 201 | 202 | extern Date; 203 | 204 | let start = new Date(); 205 | let res = run(); 206 | let elapsed = new Date() - start; 207 | 208 | if (res - (-0.1690693) < 0.00001) 209 | print("metric time " + elapsed); 210 | else 211 | print("error nbody result expecting -0.1690693 got " + res); 212 | 213 | 214 | extern memory; 215 | // print(memory.memcheck.report()); 216 | 217 | // let m = memory 218 | // if (m.memcheck.enabled){ 219 | // print("\n") 220 | // print(m.memcheck.report()) 221 | // } 222 | -------------------------------------------------------------------------------- /benchmarks/access-nbody.orig.js: -------------------------------------------------------------------------------- 1 | /* The Great Computer Language Shootout 2 | http://shootout.alioth.debian.org/ 3 | contributed by Isaac Gouy */ 4 | 5 | var PI = 3.141592653589793; 6 | var SOLAR_MASS = 4 * PI * PI; 7 | var DAYS_PER_YEAR = 365.24; 8 | 9 | function Body(x,y,z,vx,vy,vz,mass){ 10 | this.x = x; 11 | this.y = y; 12 | this.z = z; 13 | this.vx = vx; 14 | this.vy = vy; 15 | this.vz = vz; 16 | this.mass = mass; 17 | } 18 | 19 | Body.prototype.offsetMomentum = function(px,py,pz) { 20 | this.vx = -px / SOLAR_MASS; 21 | this.vy = -py / SOLAR_MASS; 22 | this.vz = -pz / SOLAR_MASS; 23 | return this; 24 | } 25 | 26 | function Jupiter(){ 27 | return new Body( 28 | 4.84143144246472090e+00, 29 | -1.16032004402742839e+00, 30 | -1.03622044471123109e-01, 31 | 1.66007664274403694e-03 * DAYS_PER_YEAR, 32 | 7.69901118419740425e-03 * DAYS_PER_YEAR, 33 | -6.90460016972063023e-05 * DAYS_PER_YEAR, 34 | 9.54791938424326609e-04 * SOLAR_MASS 35 | ); 36 | } 37 | 38 | function Saturn(){ 39 | return new Body( 40 | 8.34336671824457987e+00, 41 | 4.12479856412430479e+00, 42 | -4.03523417114321381e-01, 43 | -2.76742510726862411e-03 * DAYS_PER_YEAR, 44 | 4.99852801234917238e-03 * DAYS_PER_YEAR, 45 | 2.30417297573763929e-05 * DAYS_PER_YEAR, 46 | 2.85885980666130812e-04 * SOLAR_MASS 47 | ); 48 | } 49 | 50 | function Uranus(){ 51 | return new Body( 52 | 1.28943695621391310e+01, 53 | -1.51111514016986312e+01, 54 | -2.23307578892655734e-01, 55 | 2.96460137564761618e-03 * DAYS_PER_YEAR, 56 | 2.37847173959480950e-03 * DAYS_PER_YEAR, 57 | -2.96589568540237556e-05 * DAYS_PER_YEAR, 58 | 4.36624404335156298e-05 * SOLAR_MASS 59 | ); 60 | } 61 | 62 | function Neptune(){ 63 | return new Body( 64 | 1.53796971148509165e+01, 65 | -2.59193146099879641e+01, 66 | 1.79258772950371181e-01, 67 | 2.68067772490389322e-03 * DAYS_PER_YEAR, 68 | 1.62824170038242295e-03 * DAYS_PER_YEAR, 69 | -9.51592254519715870e-05 * DAYS_PER_YEAR, 70 | 5.15138902046611451e-05 * SOLAR_MASS 71 | ); 72 | } 73 | 74 | function Sun(){ 75 | return new Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS); 76 | } 77 | 78 | 79 | function NBodySystem(bodies){ 80 | this.bodies = bodies; 81 | var px = 0.0; 82 | var py = 0.0; 83 | var pz = 0.0; 84 | var size = this.bodies.length; 85 | /* BEGIN LOOP */ 86 | for (var i=0; inext = prev; 25 | head->val = i; 26 | } 27 | 28 | let double sum = 0; 29 | for (let int i = 0; i < n; ++i) { 30 | let Node *prev = head; 31 | sum += head->val; 32 | head = head->next; 33 | delete prev; 34 | } 35 | 36 | return new Date() - start; 37 | } 38 | 39 | function benchObject() { 40 | let start = new Date(); 41 | let head; 42 | for (let i = 0; i < n; ++i) { 43 | let prev = head; 44 | head = new ObjNode(); 45 | head.next = prev; 46 | head.val = i; 47 | } 48 | 49 | let sum = 0; 50 | for (let i = 0; i < n; ++i) { 51 | sum += head.val; 52 | head = head.next; 53 | } 54 | 55 | return new Date() - start; 56 | } 57 | 58 | extern print; 59 | if (typeof print === "undefined") { 60 | extern console; 61 | print = console.log; 62 | } 63 | 64 | // Warm up the JIT. 65 | benchStruct(); benchStruct(); 66 | benchObject(); benchObject(); 67 | 68 | let dt; 69 | 70 | dt = 0; 71 | for (let i = 0; i < 25; ++i) { 72 | dt += benchStruct(); 73 | } 74 | print("struct with 32 bytes of padding " + dt / 25); 75 | 76 | dt = 0; 77 | for (let i = 0; i < 25; ++i) { 78 | dt += benchObject(); 79 | } 80 | print("object with 4 extra properties " + dt / 25); 81 | 82 | let uint *x; 83 | *x 84 | 85 | let uint *leak = new uint; 86 | 87 | // let m = memory 88 | // if (m.memcheck.enabled){ 89 | // print("\n") 90 | // print(m.memcheck.report()) 91 | // } 92 | -------------------------------------------------------------------------------- /bin/ljc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var dir = path.join(path.dirname(fs.realpathSync(__filename)), '../src'); 6 | 7 | require(path.join(dir, 'ljc')).cli(); 8 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | lljs.org -------------------------------------------------------------------------------- /docs/css/screen.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 16px; 3 | line-height: 22px; 4 | color: #333; 5 | background: #f6f6f6 url(../images/background.png); 6 | font-family: "PT Serif", "Georgia", "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important; 7 | } 8 | 9 | .container { 10 | width: 1050px; 11 | margin: 0; 12 | padding: 30px 0px 40px 40px; 13 | text-align: justify; 14 | } 15 | 16 | code, pre, tt, textarea { 17 | font-family: Monaco, Consolas, "Lucida Console", monospace; 18 | font-size: 12px; 19 | /* font-weight: bold; */ 20 | line-height: 18px; 21 | color: #255; 22 | white-space: pre-wrap; 23 | word-wrap: break-word; 24 | } 25 | 26 | tt { 27 | // display: inline-block; 28 | background: #fff; 29 | border: 1px solid #dedede; 30 | padding: 0px 0.2em; 31 | } 32 | 33 | pre { 34 | padding: 3px 0 3px 12px; 35 | font-size: 12px; 36 | } 37 | 38 | .jcCode { 39 | background: #f6f6f6 url(../images/background.png); 40 | padding: 10px; 41 | } 42 | 43 | .jcResult { 44 | line-height: 14px; 45 | width: 78ex; 46 | font-size: 11px; 47 | } 48 | 49 | .jcToolbar { 50 | background-color: white; 51 | } 52 | 53 | .jcToolbar tr td { 54 | padding: 10px; 55 | } 56 | 57 | .example textarea { 58 | resize: vertical; 59 | cursor: text; 60 | } 61 | 62 | .example td { 63 | padding: 0px; 64 | vertical-align: top; 65 | } 66 | 67 | .example td + td { 68 | border-left: 2px dotted #d8d8d8; 69 | } 70 | 71 | table.example { 72 | position: relative; 73 | background: #fff; 74 | border: 2px solid #d8d8d8; 75 | -webkit-box-shadow: 0px 0px 4px rgba(0,0,0,0.23); 76 | -moz-box-shadow: 0px 0px 4px rgba(0,0,0,0.23); 77 | box-shadow: 0px 0px 4px rgba(0,0,0,0.23); 78 | zoom: 1; 79 | } 80 | 81 | .toolbar { 82 | margin-top: 4px; 83 | } 84 | 85 | /*----------------------------- Mini Buttons ---------------------------------*/ 86 | .minibutton { 87 | float: left; 88 | font-family: "Lucida Console", monospace; 89 | font-size: 8px; 90 | cursor: pointer; 91 | color: #333; 92 | text-shadow: #eee 0 1px 1px; 93 | font-weight: bold; 94 | font-size: 11px; 95 | line-height: 11px; 96 | padding: 5px 10px 6px; 97 | height: 11px; 98 | text-align: center; 99 | -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; 100 | box-shadow: 0 1px 2px rgba(0,0,0,0.2); -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.2); 101 | border: 1px solid #b2b2b2; border-top-color: #c9c9c9; border-bottom-color: #9a9a9a; 102 | } 103 | .minibutton:active { 104 | border-color: #aaa; 105 | box-shadow: 0 1px 2px #e4e4e4; -webkit-box-shadow: 0 1px 2px #e4e4e4; -moz-box-shadow: 0 1px 2px #e4e4e4; 106 | } 107 | .minibutton::selection { 108 | background: transparent; 109 | } 110 | .minibutton ::-moz-selection { 111 | background: transparent; 112 | } 113 | .minibutton.ok { 114 | color: #fff; 115 | border-color: #4ba47c; border-top-color: #53b388; border-bottom-color: #459671; 116 | text-shadow: #aaa 0 -1px 0; 117 | } 118 | .minibutton.dark { 119 | border: 0; 120 | color: #fff; 121 | box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none; 122 | text-shadow: none; 123 | } 124 | -------------------------------------------------------------------------------- /docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LLJS : Low-Level JavaScript 4 | 5 | 6 | 7 | 8 | 9 | Fork me on GitHub 10 | Mozilla 11 |
12 |
13 |

K&R Malloc vs. JS Object Allocation

14 | 15 |

16 | 17 | 85 |
 86 | 
 87 | const int n = 250000; // Number of object allocations.
 88 | const int m = 300;    // Number of balls.
 89 | 
 90 | function drawHook() {
 91 |   benchObject();
 92 |   // benchStruct();
 93 | }
 94 | 
 95 | extern document, window, Math, Date, trace, latency, cancelAnimationFrame, requestAnimationFrame;
 96 | 
 97 | let balls = [];
 98 | let radius = 10, width = 640, height = 640;
 99 | for (let i = 0; i < m; i++) {
100 |   let dx = 0.5 - Math.random();
101 |   let dy = 0.5 - Math.random();
102 |   balls.push({x: width / 2, y: height / 2, dx: dx, dy: dy, radius: 5 + Math.random() * 5});
103 | }
104 | 
105 | let ctx = document.getElementById('canvas').getContext('2d');
106 | 
107 | struct Node {
108 |   Node *next;
109 |   int val;
110 |   double pad1, pad2, pad3, pad4;
111 | };
112 | 
113 | function ObjNode() {
114 |   this.next = null;
115 |   this.val = 0;
116 |   this.pad1 = 0;
117 |   this.pad2 = 0;
118 |   this.pad3 = 0;
119 |   this.pad4 = 0;
120 | }
121 | 
122 | function benchStruct() {
123 |   let Node *head;
124 |   for (let int i = 0; i < n; ++i) {
125 |     let Node *prev = head;
126 |     head = new Node;
127 |     head->next = prev;
128 |     head->val = i;
129 |   }
130 | 
131 |   let double sum = 0;
132 |   for (let int i = 0; i < n; ++i) {
133 |     let Node *prev = head;
134 |     sum += head->val;
135 |     head = head->next;
136 |     delete prev;
137 |   }
138 | }
139 | 
140 | function benchObject() {
141 |   let head;
142 |   for (let i = 0; i < n; ++i) {
143 |     let prev = head;
144 |     head = new ObjNode();
145 |     head.next = prev;
146 |     head.val = i;
147 |   }
148 | 
149 |   let sum = 0;
150 |   for (let i = 0; i < n; ++i) {
151 |     sum += head.val;
152 |     head = head.next;
153 |   }
154 | }
155 | 
156 | let last = new Date();
157 | let request;
158 | function draw() {
159 |   latency.tick();
160 |   ctx.clearRect(0, 0, width, height);
161 |   drawHook();
162 |   let curr = new Date();
163 |   let elapsed = (curr - last) / 10;
164 |   last = curr;
165 |   for (let i = 0; i < balls.length; i++) {
166 |     let ball = balls[i];
167 |     let dx = ball.dx * elapsed;
168 |     let dy = ball.dy * elapsed;
169 |     let nx = ball.x + dx;
170 |     let ny = ball.y + dy;
171 |     if (nx < ball.radius || nx > width - ball.radius) {
172 |       ball.dx *= -1;
173 |       dx *= -1;
174 |     }
175 |     if (ny < ball.radius || ny > height - ball.radius) {
176 |       ball.dy *= -1;
177 |       dy *= -1;
178 |     }
179 |     ball.x += dx;
180 |     ball.y += dy;
181 |     ctx.beginPath();
182 |     ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2, true);
183 |     ctx.closePath();
184 |     ctx.fill();
185 |   }
186 |   request = requestAnimationFrame(draw);
187 | }
188 | if (request) {
189 |   cancelAnimationFrame(request);
190 | }
191 | draw();
192 | 
193 |     
194 |
195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /docs/images/arrays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/arrays.png -------------------------------------------------------------------------------- /docs/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/background.png -------------------------------------------------------------------------------- /docs/images/banding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/banding.png -------------------------------------------------------------------------------- /docs/images/button_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/button_bg.png -------------------------------------------------------------------------------- /docs/images/button_bg_dark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/button_bg_dark.gif -------------------------------------------------------------------------------- /docs/images/button_bg_green.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/button_bg_green.gif -------------------------------------------------------------------------------- /docs/images/fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/fork.png -------------------------------------------------------------------------------- /docs/images/heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/heap.png -------------------------------------------------------------------------------- /docs/images/mozilla.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/mozilla.png -------------------------------------------------------------------------------- /docs/images/screenshadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlongster/LLJS/6a24c33cd9adf61a4a33ba85cb60c208adc9edff/docs/images/screenshadow.png -------------------------------------------------------------------------------- /docs/lljs: -------------------------------------------------------------------------------- 1 | ../src -------------------------------------------------------------------------------- /docs/vendor/cm/lib/codemirror.css: -------------------------------------------------------------------------------- 1 | .CodeMirror { 2 | /* line-height: 1em; */ 3 | line-height: 14px; 4 | font-family: monospace; 5 | font-family: Consolas, "Lucida Console", monospace; 6 | font-size: 12px; 7 | } 8 | 9 | .CodeMirror-scroll { 10 | height: auto; 11 | overflow-y: visible; 12 | overflow-x: auto; 13 | width: 92ex; 14 | padding: 4px; 15 | 16 | /* This is needed to prevent an IE[67] bug where the scrolled content 17 | is visible outside of the scrolling box. */ 18 | position: relative; 19 | outline: none; 20 | } 21 | 22 | .CodeMirror-gutter { 23 | position: absolute; left: 0; top: 0; 24 | z-index: 10; 25 | background-color: #f7f7f7; 26 | border-right: 1px solid #eee; 27 | min-width: 3em; 28 | height: 100% !important; 29 | } 30 | .CodeMirror-gutter-text { 31 | color: #aac; 32 | text-align: right; 33 | padding: .4em .2em .4em .4em; 34 | white-space: pre !important; 35 | } 36 | .CodeMirror-lines { 37 | padding: .4em; 38 | white-space: pre; 39 | } 40 | 41 | .CodeMirror pre { 42 | -moz-border-radius: 0; 43 | -webkit-border-radius: 0; 44 | -o-border-radius: 0; 45 | border-radius: 0; 46 | border-width: 0; margin: 0; padding: 0; background: transparent; 47 | font-family: inherit; 48 | font-size: inherit; 49 | padding: 0; margin: 0; 50 | white-space: pre; 51 | word-wrap: normal; 52 | line-height: inherit; 53 | color: inherit; 54 | } 55 | 56 | .CodeMirror-wrap pre { 57 | word-wrap: break-word; 58 | white-space: pre-wrap; 59 | word-break: normal; 60 | } 61 | .CodeMirror-wrap .CodeMirror-scroll { 62 | overflow-x: hidden; 63 | } 64 | 65 | .CodeMirror textarea { 66 | outline: none !important; 67 | } 68 | 69 | .CodeMirror pre.CodeMirror-cursor { 70 | z-index: 10; 71 | position: absolute; 72 | visibility: hidden; 73 | border-left: 1px solid black; 74 | border-right: none; 75 | width: 0; 76 | } 77 | .cm-keymap-fat-cursor pre.CodeMirror-cursor { 78 | width: auto; 79 | border: 0; 80 | background: transparent; 81 | background: rgba(0, 200, 0, .4); 82 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); 83 | } 84 | /* Kludge to turn off filter in ie9+, which also accepts rgba */ 85 | .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { 86 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 87 | } 88 | .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} 89 | .CodeMirror-focused pre.CodeMirror-cursor { 90 | visibility: visible; 91 | } 92 | 93 | div.CodeMirror-selected { background: #d9d9d9; } 94 | .CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; } 95 | 96 | .CodeMirror-searching { 97 | background: #ffa; 98 | background: rgba(255, 255, 0, .4); 99 | } 100 | 101 | /* Default theme */ 102 | 103 | .cm-s-default span.cm-keyword {color: #708;} 104 | .cm-s-default span.cm-atom {color: #219;} 105 | .cm-s-default span.cm-number {color: #164;} 106 | .cm-s-default span.cm-def {color: #00f;} 107 | .cm-s-default span.cm-variable {color: black;} 108 | .cm-s-default span.cm-variable-2 {color: #05a;} 109 | .cm-s-default span.cm-variable-3 {color: #085;} 110 | .cm-s-default span.cm-property {color: black;} 111 | .cm-s-default span.cm-operator {color: black;} 112 | .cm-s-default span.cm-comment {color: #a50;} 113 | .cm-s-default span.cm-string {color: #a11;} 114 | .cm-s-default span.cm-string-2 {color: #f50;} 115 | .cm-s-default span.cm-meta {color: #555;} 116 | .cm-s-default span.cm-error {color: #f00;} 117 | .cm-s-default span.cm-qualifier {color: #555;} 118 | .cm-s-default span.cm-builtin {color: #30a;} 119 | .cm-s-default span.cm-bracket {color: #cc7;} 120 | .cm-s-default span.cm-tag {color: #170;} 121 | .cm-s-default span.cm-attribute {color: #00c;} 122 | .cm-s-default span.cm-header {color: blue;} 123 | .cm-s-default span.cm-quote {color: #090;} 124 | .cm-s-default span.cm-hr {color: #999;} 125 | .cm-s-default span.cm-link {color: #00c;} 126 | 127 | span.cm-header, span.cm-strong {font-weight: bold;} 128 | span.cm-em {font-style: italic;} 129 | span.cm-emstrong {font-style: italic; font-weight: bold;} 130 | span.cm-link {text-decoration: underline;} 131 | 132 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 133 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 134 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/closetag.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tag-closer extension for CodeMirror. 3 | * 4 | * This extension adds a "closeTag" utility function that can be used with key bindings to 5 | * insert a matching end tag after the ">" character of a start tag has been typed. It can 6 | * also complete " 17 | * Contributed under the same license terms as CodeMirror. 18 | */ 19 | (function() { 20 | /** Option that allows tag closing behavior to be toggled. Default is true. */ 21 | CodeMirror.defaults['closeTagEnabled'] = true; 22 | 23 | /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */ 24 | CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul']; 25 | 26 | /** 27 | * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass. 28 | * - cm: The editor instance. 29 | * - ch: The character being processed. 30 | * - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option. 31 | * Pass false to disable indentation. Pass an array to override the default list of tag names. 32 | */ 33 | CodeMirror.defineExtension("closeTag", function(cm, ch, indent) { 34 | if (!cm.getOption('closeTagEnabled')) { 35 | throw CodeMirror.Pass; 36 | } 37 | 38 | var mode = cm.getOption('mode'); 39 | 40 | if (mode == 'text/html') { 41 | 42 | /* 43 | * Relevant structure of token: 44 | * 45 | * htmlmixed 46 | * className 47 | * state 48 | * htmlState 49 | * type 50 | * context 51 | * tagName 52 | * mode 53 | * 54 | * xml 55 | * className 56 | * state 57 | * tagName 58 | * type 59 | */ 60 | 61 | var pos = cm.getCursor(); 62 | var tok = cm.getTokenAt(pos); 63 | var state = tok.state; 64 | 65 | if (state.mode && state.mode != 'html') { 66 | throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode. 67 | } 68 | 69 | if (ch == '>') { 70 | var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml 71 | 72 | if (tok.className == 'tag' && type == 'closeTag') { 73 | throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag. 74 | } 75 | 76 | cm.replaceSelection('>'); // Mode state won't update until we finish the tag. 77 | pos = {line: pos.line, ch: pos.ch + 1}; 78 | cm.setCursor(pos); 79 | 80 | tok = cm.getTokenAt(cm.getCursor()); 81 | state = tok.state; 82 | type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml 83 | 84 | if (tok.className == 'tag' && type != 'selfcloseTag') { 85 | var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml 86 | if (tagName.length > 0) { 87 | insertEndTag(cm, indent, pos, tagName); 88 | } 89 | return; 90 | } 91 | 92 | // Undo the '>' insert and allow cm to handle the key instead. 93 | cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos); 94 | cm.replaceSelection(""); 95 | 96 | } else if (ch == '/') { 97 | if (tok.className == 'tag' && tok.string == '<') { 98 | var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for ' 0) { 100 | completeEndTag(cm, pos, tagName); 101 | return; 102 | } 103 | } 104 | } 105 | 106 | } 107 | 108 | throw CodeMirror.Pass; // Bubble if not handled 109 | }); 110 | 111 | function insertEndTag(cm, indent, pos, tagName) { 112 | if (shouldIndent(cm, indent, tagName)) { 113 | cm.replaceSelection('\n\n', 'end'); 114 | cm.indentLine(pos.line + 1); 115 | cm.indentLine(pos.line + 2); 116 | cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length}); 117 | } else { 118 | cm.replaceSelection(''); 119 | cm.setCursor(pos); 120 | } 121 | } 122 | 123 | function shouldIndent(cm, indent, tagName) { 124 | if (typeof indent == 'undefined' || indent == null || indent == true) { 125 | indent = cm.getOption('closeTagIndent'); 126 | } 127 | if (!indent) { 128 | indent = []; 129 | } 130 | return indexOf(indent, tagName.toLowerCase()) != -1; 131 | } 132 | 133 | // C&P from codemirror.js...would be nice if this were visible to utilities. 134 | function indexOf(collection, elt) { 135 | if (collection.indexOf) return collection.indexOf(elt); 136 | for (var i = 0, e = collection.length; i < e; ++i) 137 | if (collection[i] == elt) return i; 138 | return -1; 139 | } 140 | 141 | function completeEndTag(cm, pos, tagName) { 142 | cm.replaceSelection('/' + tagName + '>'); 143 | cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 }); 144 | } 145 | 146 | })(); 147 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/dialog.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-dialog { 2 | position: relative; 3 | } 4 | 5 | .CodeMirror-dialog > div { 6 | position: absolute; 7 | top: 0; left: 0; right: 0; 8 | background: white; 9 | border-bottom: 1px solid #eee; 10 | z-index: 15; 11 | padding: .1em .8em; 12 | overflow: hidden; 13 | color: #333; 14 | } 15 | 16 | .CodeMirror-dialog input { 17 | border: none; 18 | outline: none; 19 | background: transparent; 20 | width: 20em; 21 | color: inherit; 22 | font-family: monospace; 23 | } 24 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/dialog.js: -------------------------------------------------------------------------------- 1 | // Open simple dialogs on top of an editor. Relies on dialog.css. 2 | 3 | (function() { 4 | function dialogDiv(cm, template) { 5 | var wrap = cm.getWrapperElement(); 6 | var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild); 7 | dialog.className = "CodeMirror-dialog"; 8 | dialog.innerHTML = '
' + template + '
'; 9 | return dialog; 10 | } 11 | 12 | CodeMirror.defineExtension("openDialog", function(template, callback) { 13 | var dialog = dialogDiv(this, template); 14 | var closed = false, me = this; 15 | function close() { 16 | if (closed) return; 17 | closed = true; 18 | dialog.parentNode.removeChild(dialog); 19 | } 20 | var inp = dialog.getElementsByTagName("input")[0]; 21 | if (inp) { 22 | CodeMirror.connect(inp, "keydown", function(e) { 23 | if (e.keyCode == 13 || e.keyCode == 27) { 24 | CodeMirror.e_stop(e); 25 | close(); 26 | me.focus(); 27 | if (e.keyCode == 13) callback(inp.value); 28 | } 29 | }); 30 | inp.focus(); 31 | CodeMirror.connect(inp, "blur", close); 32 | } 33 | return close; 34 | }); 35 | 36 | CodeMirror.defineExtension("openConfirm", function(template, callbacks) { 37 | var dialog = dialogDiv(this, template); 38 | var buttons = dialog.getElementsByTagName("button"); 39 | var closed = false, me = this, blurring = 1; 40 | function close() { 41 | if (closed) return; 42 | closed = true; 43 | dialog.parentNode.removeChild(dialog); 44 | me.focus(); 45 | } 46 | buttons[0].focus(); 47 | for (var i = 0; i < buttons.length; ++i) { 48 | var b = buttons[i]; 49 | (function(callback) { 50 | CodeMirror.connect(b, "click", function(e) { 51 | CodeMirror.e_preventDefault(e); 52 | close(); 53 | if (callback) callback(me); 54 | }); 55 | })(callbacks[i]); 56 | CodeMirror.connect(b, "blur", function() { 57 | --blurring; 58 | setTimeout(function() { if (blurring <= 0) close(); }, 200); 59 | }); 60 | CodeMirror.connect(b, "focus", function() { ++blurring; }); 61 | } 62 | }); 63 | })(); -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/foldcode.js: -------------------------------------------------------------------------------- 1 | // the tagRangeFinder function is 2 | // Copyright (C) 2011 by Daniel Glazman 3 | // released under the MIT license (../../LICENSE) like the rest of CodeMirror 4 | CodeMirror.tagRangeFinder = function(cm, line, hideEnd) { 5 | var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; 6 | var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; 7 | var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*"); 8 | 9 | var lineText = cm.getLine(line); 10 | var found = false; 11 | var tag = null; 12 | var pos = 0; 13 | while (!found) { 14 | pos = lineText.indexOf("<", pos); 15 | if (-1 == pos) // no tag on line 16 | return; 17 | if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag 18 | pos++; 19 | continue; 20 | } 21 | // ok we weem to have a start tag 22 | if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name... 23 | pos++; 24 | continue; 25 | } 26 | var gtPos = lineText.indexOf(">", pos + 1); 27 | if (-1 == gtPos) { // end of start tag not in line 28 | var l = line + 1; 29 | var foundGt = false; 30 | var lastLine = cm.lineCount(); 31 | while (l < lastLine && !foundGt) { 32 | var lt = cm.getLine(l); 33 | var gt = lt.indexOf(">"); 34 | if (-1 != gt) { // found a > 35 | foundGt = true; 36 | var slash = lt.lastIndexOf("/", gt); 37 | if (-1 != slash && slash < gt) { 38 | var str = lineText.substr(slash, gt - slash + 1); 39 | if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag 40 | if (hideEnd === true) l++; 41 | return l; 42 | } 43 | } 44 | } 45 | l++; 46 | } 47 | found = true; 48 | } 49 | else { 50 | var slashPos = lineText.lastIndexOf("/", gtPos); 51 | if (-1 == slashPos) { // cannot be empty tag 52 | found = true; 53 | // don't continue 54 | } 55 | else { // empty tag? 56 | // check if really empty tag 57 | var str = lineText.substr(slashPos, gtPos - slashPos + 1); 58 | if (!str.match( /\/\s*\>/ )) { // finally not empty 59 | found = true; 60 | // don't continue 61 | } 62 | } 63 | } 64 | if (found) { 65 | var subLine = lineText.substr(pos + 1); 66 | tag = subLine.match(xmlNAMERegExp); 67 | if (tag) { 68 | // we have an element name, wooohooo ! 69 | tag = tag[0]; 70 | // do we have the close tag on same line ??? 71 | if (-1 != lineText.indexOf("", pos)) // yep 72 | { 73 | found = false; 74 | } 75 | // we don't, so we have a candidate... 76 | } 77 | else 78 | found = false; 79 | } 80 | if (!found) 81 | pos++; 82 | } 83 | 84 | if (found) { 85 | var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)"; 86 | var startTagRegExp = new RegExp(startTag, "g"); 87 | var endTag = ""; 88 | var depth = 1; 89 | var l = line + 1; 90 | var lastLine = cm.lineCount(); 91 | while (l < lastLine) { 92 | lineText = cm.getLine(l); 93 | var match = lineText.match(startTagRegExp); 94 | if (match) { 95 | for (var i = 0; i < match.length; i++) { 96 | if (match[i] == endTag) 97 | depth--; 98 | else 99 | depth++; 100 | if (!depth) { 101 | if (hideEnd === true) l++; 102 | return l; 103 | } 104 | } 105 | } 106 | l++; 107 | } 108 | return; 109 | } 110 | }; 111 | 112 | CodeMirror.braceRangeFinder = function(cm, line, hideEnd) { 113 | var lineText = cm.getLine(line); 114 | var startChar = lineText.lastIndexOf("{"); 115 | if (startChar < 0 || lineText.lastIndexOf("}") > startChar) return; 116 | var tokenType = cm.getTokenAt({line: line, ch: startChar}).className; 117 | var count = 1, lastLine = cm.lineCount(), end; 118 | outer: for (var i = line + 1; i < lastLine; ++i) { 119 | var text = cm.getLine(i), pos = 0; 120 | for (;;) { 121 | var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos); 122 | if (nextOpen < 0) nextOpen = text.length; 123 | if (nextClose < 0) nextClose = text.length; 124 | pos = Math.min(nextOpen, nextClose); 125 | if (pos == text.length) break; 126 | if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) { 127 | if (pos == nextOpen) ++count; 128 | else if (!--count) { end = i; break outer; } 129 | } 130 | ++pos; 131 | } 132 | } 133 | if (end == null || end == line + 1) return; 134 | if (hideEnd === true) end++; 135 | return end; 136 | }; 137 | 138 | CodeMirror.indentRangeFinder = function(cm, line) { 139 | var tabSize = cm.getOption("tabSize"); 140 | var myIndent = cm.getLineHandle(line).indentation(tabSize), last; 141 | for (var i = line + 1, end = cm.lineCount(); i < end; ++i) { 142 | var handle = cm.getLineHandle(i); 143 | if (!/^\s*$/.test(handle.text)) { 144 | if (handle.indentation(tabSize) <= myIndent) break; 145 | last = i; 146 | } 147 | } 148 | if (!last) return null; 149 | return last + 1; 150 | }; 151 | 152 | CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) { 153 | var folded = []; 154 | if (markText == null) markText = '
%N%'; 155 | 156 | function isFolded(cm, n) { 157 | for (var i = 0; i < folded.length; ++i) { 158 | var start = cm.lineInfo(folded[i].start); 159 | if (!start) folded.splice(i--, 1); 160 | else if (start.line == n) return {pos: i, region: folded[i]}; 161 | } 162 | } 163 | 164 | function expand(cm, region) { 165 | cm.clearMarker(region.start); 166 | for (var i = 0; i < region.hidden.length; ++i) 167 | cm.showLine(region.hidden[i]); 168 | } 169 | 170 | return function(cm, line) { 171 | cm.operation(function() { 172 | var known = isFolded(cm, line); 173 | if (known) { 174 | folded.splice(known.pos, 1); 175 | expand(cm, known.region); 176 | } else { 177 | var end = rangeFinder(cm, line, hideEnd); 178 | if (end == null) return; 179 | var hidden = []; 180 | for (var i = line + 1; i < end; ++i) { 181 | var handle = cm.hideLine(i); 182 | if (handle) hidden.push(handle); 183 | } 184 | var first = cm.setMarker(line, markText); 185 | var region = {start: first, hidden: hidden}; 186 | cm.onDeleteLine(first, function() { expand(cm, region); }); 187 | folded.push(region); 188 | } 189 | }); 190 | }; 191 | }; 192 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/javascript-hint.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | function forEach(arr, f) { 3 | for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); 4 | } 5 | 6 | function arrayContains(arr, item) { 7 | if (!Array.prototype.indexOf) { 8 | var i = arr.length; 9 | while (i--) { 10 | if (arr[i] === item) { 11 | return true; 12 | } 13 | } 14 | return false; 15 | } 16 | return arr.indexOf(item) != -1; 17 | } 18 | 19 | function scriptHint(editor, keywords, getToken) { 20 | // Find the token at the cursor 21 | var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; 22 | // If it's not a 'word-style' token, ignore the token. 23 | if (!/^[\w$_]*$/.test(token.string)) { 24 | token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, 25 | className: token.string == "." ? "property" : null}; 26 | } 27 | // If it is a property, find out what it is a property of. 28 | while (tprop.className == "property") { 29 | tprop = getToken(editor, {line: cur.line, ch: tprop.start}); 30 | if (tprop.string != ".") return; 31 | tprop = getToken(editor, {line: cur.line, ch: tprop.start}); 32 | if (tprop.string == ')') { 33 | var level = 1; 34 | do { 35 | tprop = getToken(editor, {line: cur.line, ch: tprop.start}); 36 | switch (tprop.string) { 37 | case ')': level++; break; 38 | case '(': level--; break; 39 | default: break; 40 | } 41 | } while (level > 0) 42 | tprop = getToken(editor, {line: cur.line, ch: tprop.start}); 43 | if (tprop.className == 'variable') 44 | tprop.className = 'function'; 45 | else return; // no clue 46 | } 47 | if (!context) var context = []; 48 | context.push(tprop); 49 | } 50 | return {list: getCompletions(token, context, keywords), 51 | from: {line: cur.line, ch: token.start}, 52 | to: {line: cur.line, ch: token.end}}; 53 | } 54 | 55 | CodeMirror.javascriptHint = function(editor) { 56 | return scriptHint(editor, javascriptKeywords, 57 | function (e, cur) {return e.getTokenAt(cur);}); 58 | } 59 | 60 | function getCoffeeScriptToken(editor, cur) { 61 | // This getToken, it is for coffeescript, imitates the behavior of 62 | // getTokenAt method in javascript.js, that is, returning "property" 63 | // type and treat "." as indepenent token. 64 | var token = editor.getTokenAt(cur); 65 | if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { 66 | token.end = token.start; 67 | token.string = '.'; 68 | token.className = "property"; 69 | } 70 | else if (/^\.[\w$_]*$/.test(token.string)) { 71 | token.className = "property"; 72 | token.start++; 73 | token.string = token.string.replace(/\./, ''); 74 | } 75 | return token; 76 | } 77 | 78 | CodeMirror.coffeescriptHint = function(editor) { 79 | return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken); 80 | } 81 | 82 | var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + 83 | "toUpperCase toLowerCase split concat match replace search").split(" "); 84 | var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + 85 | "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); 86 | var funcProps = "prototype apply call bind".split(" "); 87 | var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + 88 | "if in instanceof new null return switch throw true try typeof var void while with").split(" "); 89 | var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + 90 | "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); 91 | 92 | function getCompletions(token, context, keywords) { 93 | var found = [], start = token.string; 94 | function maybeAdd(str) { 95 | if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str); 96 | } 97 | function gatherCompletions(obj) { 98 | if (typeof obj == "string") forEach(stringProps, maybeAdd); 99 | else if (obj instanceof Array) forEach(arrayProps, maybeAdd); 100 | else if (obj instanceof Function) forEach(funcProps, maybeAdd); 101 | for (var name in obj) maybeAdd(name); 102 | } 103 | 104 | if (context) { 105 | // If this is a property, see if it belongs to some object we can 106 | // find in the current environment. 107 | var obj = context.pop(), base; 108 | if (obj.className == "variable") 109 | base = window[obj.string]; 110 | else if (obj.className == "string") 111 | base = ""; 112 | else if (obj.className == "atom") 113 | base = 1; 114 | else if (obj.className == "function") { 115 | if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && 116 | (typeof window.jQuery == 'function')) 117 | base = window.jQuery(); 118 | else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function')) 119 | base = window._(); 120 | } 121 | while (base != null && context.length) 122 | base = base[context.pop().string]; 123 | if (base != null) gatherCompletions(base); 124 | } 125 | else { 126 | // If not, just look in the window object and any local scope 127 | // (reading into JS mode internals to get at the local variables) 128 | for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); 129 | gatherCompletions(window); 130 | forEach(keywords, maybeAdd); 131 | } 132 | return found; 133 | } 134 | })(); 135 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/loadmode.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; 3 | 4 | var loading = {}; 5 | function splitCallback(cont, n) { 6 | var countDown = n; 7 | return function() { if (--countDown == 0) cont(); } 8 | } 9 | function ensureDeps(mode, cont) { 10 | var deps = CodeMirror.modes[mode].dependencies; 11 | if (!deps) return cont(); 12 | var missing = []; 13 | for (var i = 0; i < deps.length; ++i) { 14 | if (!CodeMirror.modes.hasOwnProperty(deps[i])) 15 | missing.push(deps[i]); 16 | } 17 | if (!missing.length) return cont(); 18 | var split = splitCallback(cont, missing.length); 19 | for (var i = 0; i < missing.length; ++i) 20 | CodeMirror.requireMode(missing[i], split); 21 | } 22 | 23 | CodeMirror.requireMode = function(mode, cont) { 24 | if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont()); 25 | if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); 26 | 27 | var script = document.createElement("script"); 28 | script.src = CodeMirror.modeURL.replace(/%N/g, mode); 29 | var others = document.getElementsByTagName("script")[0]; 30 | others.parentNode.insertBefore(script, others); 31 | var list = loading[mode] = [cont]; 32 | var count = 0, poll = setInterval(function() { 33 | if (++count > 100) return clearInterval(poll); 34 | if (CodeMirror.modes.hasOwnProperty(mode)) { 35 | clearInterval(poll); 36 | loading[mode] = null; 37 | ensureDeps(mode, function() { 38 | for (var i = 0; i < list.length; ++i) list[i](); 39 | }); 40 | } 41 | }, 200); 42 | }; 43 | 44 | CodeMirror.autoLoadMode = function(instance, mode) { 45 | if (!CodeMirror.modes.hasOwnProperty(mode)) 46 | CodeMirror.requireMode(mode, function() { 47 | instance.setOption("mode", instance.getOption("mode")); 48 | }); 49 | }; 50 | }()); 51 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/match-highlighter.js: -------------------------------------------------------------------------------- 1 | // Define match-highlighter commands. Depends on searchcursor.js 2 | // Use by attaching the following function call to the onCursorActivity event: 3 | //myCodeMirror.matchHighlight(minChars); 4 | // And including a special span.CodeMirror-matchhighlight css class (also optionally a separate one for .CodeMirror-focused -- see demo matchhighlighter.html) 5 | 6 | (function() { 7 | var DEFAULT_MIN_CHARS = 2; 8 | 9 | function MatchHighlightState() { 10 | this.marked = []; 11 | } 12 | function getMatchHighlightState(cm) { 13 | return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState()); 14 | } 15 | 16 | function clearMarks(cm) { 17 | var state = getMatchHighlightState(cm); 18 | for (var i = 0; i < state.marked.length; ++i) 19 | state.marked[i].clear(); 20 | state.marked = []; 21 | } 22 | 23 | function markDocument(cm, className, minChars) { 24 | clearMarks(cm); 25 | minChars = (typeof minChars !== 'undefined' ? minChars : DEFAULT_MIN_CHARS); 26 | if (cm.somethingSelected() && cm.getSelection().replace(/^\s+|\s+$/g, "").length >= minChars) { 27 | var state = getMatchHighlightState(cm); 28 | var query = cm.getSelection(); 29 | cm.operation(function() { 30 | if (cm.lineCount() < 2000) { // This is too expensive on big documents. 31 | for (var cursor = cm.getSearchCursor(query); cursor.findNext();) { 32 | //Only apply matchhighlight to the matches other than the one actually selected 33 | if (!(cursor.from().line === cm.getCursor(true).line && cursor.from().ch === cm.getCursor(true).ch)) 34 | state.marked.push(cm.markText(cursor.from(), cursor.to(), className)); 35 | } 36 | } 37 | }); 38 | } 39 | } 40 | 41 | CodeMirror.defineExtension("matchHighlight", function(className, minChars) { 42 | markDocument(this, className, minChars); 43 | }); 44 | })(); 45 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/overlay.js: -------------------------------------------------------------------------------- 1 | // Utility function that allows modes to be combined. The mode given 2 | // as the base argument takes care of most of the normal mode 3 | // functionality, but a second (typically simple) mode is used, which 4 | // can override the style of text. Both modes get to parse all of the 5 | // text, but when both assign a non-null style to a piece of code, the 6 | // overlay wins, unless the combine argument was true, in which case 7 | // the styles are combined. 8 | 9 | CodeMirror.overlayParser = function(base, overlay, combine) { 10 | return { 11 | startState: function() { 12 | return { 13 | base: CodeMirror.startState(base), 14 | overlay: CodeMirror.startState(overlay), 15 | basePos: 0, baseCur: null, 16 | overlayPos: 0, overlayCur: null 17 | }; 18 | }, 19 | copyState: function(state) { 20 | return { 21 | base: CodeMirror.copyState(base, state.base), 22 | overlay: CodeMirror.copyState(overlay, state.overlay), 23 | basePos: state.basePos, baseCur: null, 24 | overlayPos: state.overlayPos, overlayCur: null 25 | }; 26 | }, 27 | 28 | token: function(stream, state) { 29 | if (stream.start == state.basePos) { 30 | state.baseCur = base.token(stream, state.base); 31 | state.basePos = stream.pos; 32 | } 33 | if (stream.start == state.overlayPos) { 34 | stream.pos = stream.start; 35 | state.overlayCur = overlay.token(stream, state.overlay); 36 | state.overlayPos = stream.pos; 37 | } 38 | stream.pos = Math.min(state.basePos, state.overlayPos); 39 | if (stream.eol()) state.basePos = state.overlayPos = 0; 40 | 41 | if (state.overlayCur == null) return state.baseCur; 42 | if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur; 43 | else return state.overlayCur; 44 | }, 45 | 46 | indent: base.indent && function(state, textAfter) { 47 | return base.indent(state.base, textAfter); 48 | }, 49 | electricChars: base.electricChars 50 | }; 51 | }; 52 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/runmode.js: -------------------------------------------------------------------------------- 1 | CodeMirror.runMode = function(string, modespec, callback, options) { 2 | var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); 3 | var isNode = callback.nodeType == 1; 4 | var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; 5 | if (isNode) { 6 | var node = callback, accum = [], col = 0; 7 | callback = function(text, style) { 8 | if (text == "\n") { 9 | accum.push("
"); 10 | col = 0; 11 | return; 12 | } 13 | var escaped = ""; 14 | // HTML-escape and replace tabs 15 | for (var pos = 0;;) { 16 | var idx = text.indexOf("\t", pos); 17 | if (idx == -1) { 18 | escaped += CodeMirror.htmlEscape(text.slice(pos)); 19 | col += text.length - pos; 20 | break; 21 | } else { 22 | col += idx - pos; 23 | escaped += CodeMirror.htmlEscape(text.slice(pos, idx)); 24 | var size = tabSize - col % tabSize; 25 | col += size; 26 | for (var i = 0; i < size; ++i) escaped += " "; 27 | pos = idx + 1; 28 | } 29 | } 30 | 31 | if (style) 32 | accum.push("" + escaped + ""); 33 | else 34 | accum.push(escaped); 35 | } 36 | } 37 | var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode); 38 | for (var i = 0, e = lines.length; i < e; ++i) { 39 | if (i) callback("\n"); 40 | var stream = new CodeMirror.StringStream(lines[i]); 41 | while (!stream.eol()) { 42 | var style = mode.token(stream, state); 43 | callback(stream.current(), style, i, stream.start); 44 | stream.start = stream.pos; 45 | } 46 | } 47 | if (isNode) 48 | node.innerHTML = accum.join(""); 49 | }; 50 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/search.js: -------------------------------------------------------------------------------- 1 | // Define search commands. Depends on dialog.js or another 2 | // implementation of the openDialog method. 3 | 4 | // Replace works a little oddly -- it will do the replace on the next 5 | // Ctrl-G (or whatever is bound to findNext) press. You prevent a 6 | // replace by making sure the match is no longer selected when hitting 7 | // Ctrl-G. 8 | 9 | (function() { 10 | function SearchState() { 11 | this.posFrom = this.posTo = this.query = null; 12 | this.marked = []; 13 | } 14 | function getSearchState(cm) { 15 | return cm._searchState || (cm._searchState = new SearchState()); 16 | } 17 | function dialog(cm, text, shortText, f) { 18 | if (cm.openDialog) cm.openDialog(text, f); 19 | else f(prompt(shortText, "")); 20 | } 21 | function confirmDialog(cm, text, shortText, fs) { 22 | if (cm.openConfirm) cm.openConfirm(text, fs); 23 | else if (confirm(shortText)) fs[0](); 24 | } 25 | function parseQuery(query) { 26 | var isRE = query.match(/^\/(.*)\/$/); 27 | return isRE ? new RegExp(isRE[1]) : query; 28 | } 29 | var queryDialog = 30 | 'Search: (Use /re/ syntax for regexp search)'; 31 | function doSearch(cm, rev) { 32 | var state = getSearchState(cm); 33 | if (state.query) return findNext(cm, rev); 34 | dialog(cm, queryDialog, "Search for:", function(query) { 35 | cm.operation(function() { 36 | if (!query || state.query) return; 37 | state.query = parseQuery(query); 38 | if (cm.lineCount() < 2000) { // This is too expensive on big documents. 39 | for (var cursor = cm.getSearchCursor(query); cursor.findNext();) 40 | state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching")); 41 | } 42 | state.posFrom = state.posTo = cm.getCursor(); 43 | findNext(cm, rev); 44 | }); 45 | }); 46 | } 47 | function findNext(cm, rev) {cm.operation(function() { 48 | var state = getSearchState(cm); 49 | var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo); 50 | if (!cursor.find(rev)) { 51 | cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0}); 52 | if (!cursor.find(rev)) return; 53 | } 54 | cm.setSelection(cursor.from(), cursor.to()); 55 | state.posFrom = cursor.from(); state.posTo = cursor.to(); 56 | })} 57 | function clearSearch(cm) {cm.operation(function() { 58 | var state = getSearchState(cm); 59 | if (!state.query) return; 60 | state.query = null; 61 | for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); 62 | state.marked.length = 0; 63 | })} 64 | 65 | var replaceQueryDialog = 66 | 'Replace: (Use /re/ syntax for regexp search)'; 67 | var replacementQueryDialog = 'With: '; 68 | var doReplaceConfirm = "Replace? "; 69 | function replace(cm, all) { 70 | dialog(cm, replaceQueryDialog, "Replace:", function(query) { 71 | if (!query) return; 72 | query = parseQuery(query); 73 | dialog(cm, replacementQueryDialog, "Replace with:", function(text) { 74 | if (all) { 75 | cm.compoundChange(function() { cm.operation(function() { 76 | for (var cursor = cm.getSearchCursor(query); cursor.findNext();) { 77 | if (typeof query != "string") { 78 | var match = cm.getRange(cursor.from(), cursor.to()).match(query); 79 | cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];})); 80 | } else cursor.replace(text); 81 | } 82 | })}); 83 | } else { 84 | clearSearch(cm); 85 | var cursor = cm.getSearchCursor(query, cm.getCursor()); 86 | function advance() { 87 | var start = cursor.from(), match; 88 | if (!(match = cursor.findNext())) { 89 | cursor = cm.getSearchCursor(query); 90 | if (!(match = cursor.findNext()) || 91 | (cursor.from().line == start.line && cursor.from().ch == start.ch)) return; 92 | } 93 | cm.setSelection(cursor.from(), cursor.to()); 94 | confirmDialog(cm, doReplaceConfirm, "Replace?", 95 | [function() {doReplace(match);}, advance]); 96 | } 97 | function doReplace(match) { 98 | cursor.replace(typeof query == "string" ? text : 99 | text.replace(/\$(\d)/, function(w, i) {return match[i];})); 100 | advance(); 101 | } 102 | advance(); 103 | } 104 | }); 105 | }); 106 | } 107 | 108 | CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; 109 | CodeMirror.commands.findNext = doSearch; 110 | CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; 111 | CodeMirror.commands.clearSearch = clearSearch; 112 | CodeMirror.commands.replace = replace; 113 | CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; 114 | })(); 115 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/searchcursor.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | function SearchCursor(cm, query, pos, caseFold) { 3 | this.atOccurrence = false; this.cm = cm; 4 | if (caseFold == null && typeof query == "string") caseFold = false; 5 | 6 | pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0}; 7 | this.pos = {from: pos, to: pos}; 8 | 9 | // The matches method is filled in based on the type of query. 10 | // It takes a position and a direction, and returns an object 11 | // describing the next occurrence of the query, or null if no 12 | // more matches were found. 13 | if (typeof query != "string") // Regexp match 14 | this.matches = function(reverse, pos) { 15 | if (reverse) { 16 | var line = cm.getLine(pos.line).slice(0, pos.ch), match = line.match(query), start = 0; 17 | while (match) { 18 | var ind = line.indexOf(match[0]); 19 | start += ind; 20 | line = line.slice(ind + 1); 21 | var newmatch = line.match(query); 22 | if (newmatch) match = newmatch; 23 | else break; 24 | start++; 25 | } 26 | } 27 | else { 28 | var line = cm.getLine(pos.line).slice(pos.ch), match = line.match(query), 29 | start = match && pos.ch + line.indexOf(match[0]); 30 | } 31 | if (match) 32 | return {from: {line: pos.line, ch: start}, 33 | to: {line: pos.line, ch: start + match[0].length}, 34 | match: match}; 35 | }; 36 | else { // String query 37 | if (caseFold) query = query.toLowerCase(); 38 | var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; 39 | var target = query.split("\n"); 40 | // Different methods for single-line and multi-line queries 41 | if (target.length == 1) 42 | this.matches = function(reverse, pos) { 43 | var line = fold(cm.getLine(pos.line)), len = query.length, match; 44 | if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1) 45 | : (match = line.indexOf(query, pos.ch)) != -1) 46 | return {from: {line: pos.line, ch: match}, 47 | to: {line: pos.line, ch: match + len}}; 48 | }; 49 | else 50 | this.matches = function(reverse, pos) { 51 | var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln)); 52 | var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match)); 53 | if (reverse ? offsetA >= pos.ch || offsetA != match.length 54 | : offsetA <= pos.ch || offsetA != line.length - match.length) 55 | return; 56 | for (;;) { 57 | if (reverse ? !ln : ln == cm.lineCount() - 1) return; 58 | line = fold(cm.getLine(ln += reverse ? -1 : 1)); 59 | match = target[reverse ? --idx : ++idx]; 60 | if (idx > 0 && idx < target.length - 1) { 61 | if (line != match) return; 62 | else continue; 63 | } 64 | var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length); 65 | if (reverse ? offsetB != line.length - match.length : offsetB != match.length) 66 | return; 67 | var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB}; 68 | return {from: reverse ? end : start, to: reverse ? start : end}; 69 | } 70 | }; 71 | } 72 | } 73 | 74 | SearchCursor.prototype = { 75 | findNext: function() {return this.find(false);}, 76 | findPrevious: function() {return this.find(true);}, 77 | 78 | find: function(reverse) { 79 | var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to); 80 | function savePosAndFail(line) { 81 | var pos = {line: line, ch: 0}; 82 | self.pos = {from: pos, to: pos}; 83 | self.atOccurrence = false; 84 | return false; 85 | } 86 | 87 | for (;;) { 88 | if (this.pos = this.matches(reverse, pos)) { 89 | this.atOccurrence = true; 90 | return this.pos.match || true; 91 | } 92 | if (reverse) { 93 | if (!pos.line) return savePosAndFail(0); 94 | pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length}; 95 | } 96 | else { 97 | var maxLine = this.cm.lineCount(); 98 | if (pos.line == maxLine - 1) return savePosAndFail(maxLine); 99 | pos = {line: pos.line+1, ch: 0}; 100 | } 101 | } 102 | }, 103 | 104 | from: function() {if (this.atOccurrence) return this.pos.from;}, 105 | to: function() {if (this.atOccurrence) return this.pos.to;}, 106 | 107 | replace: function(newText) { 108 | var self = this; 109 | if (this.atOccurrence) 110 | self.pos.to = this.cm.replaceRange(newText, self.pos.from, self.pos.to); 111 | } 112 | }; 113 | 114 | CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { 115 | return new SearchCursor(this, query, pos, caseFold); 116 | }); 117 | })(); 118 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/simple-hint.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-completions { 2 | position: absolute; 3 | z-index: 10; 4 | overflow: hidden; 5 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); 6 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); 7 | box-shadow: 2px 3px 5px rgba(0,0,0,.2); 8 | } 9 | .CodeMirror-completions select { 10 | background: #fafafa; 11 | outline: none; 12 | border: none; 13 | padding: 0; 14 | margin: 0; 15 | font-family: monospace; 16 | } 17 | -------------------------------------------------------------------------------- /docs/vendor/cm/lib/util/simple-hint.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | CodeMirror.simpleHint = function(editor, getHints) { 3 | // We want a single cursor position. 4 | if (editor.somethingSelected()) return; 5 | var result = getHints(editor); 6 | if (!result || !result.list.length) return; 7 | var completions = result.list; 8 | function insert(str) { 9 | editor.replaceRange(str, result.from, result.to); 10 | } 11 | // When there is only one completion, use it directly. 12 | if (completions.length == 1) {insert(completions[0]); return true;} 13 | 14 | // Build the select widget 15 | var complete = document.createElement("div"); 16 | complete.className = "CodeMirror-completions"; 17 | var sel = complete.appendChild(document.createElement("select")); 18 | // Opera doesn't move the selection when pressing up/down in a 19 | // multi-select, but it does properly support the size property on 20 | // single-selects, so no multi-select is necessary. 21 | if (!window.opera) sel.multiple = true; 22 | for (var i = 0; i < completions.length; ++i) { 23 | var opt = sel.appendChild(document.createElement("option")); 24 | opt.appendChild(document.createTextNode(completions[i])); 25 | } 26 | sel.firstChild.selected = true; 27 | sel.size = Math.min(10, completions.length); 28 | var pos = editor.cursorCoords(); 29 | complete.style.left = pos.x + "px"; 30 | complete.style.top = pos.yBot + "px"; 31 | document.body.appendChild(complete); 32 | // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. 33 | var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); 34 | if(winW - pos.x < sel.clientWidth) 35 | complete.style.left = (pos.x - sel.clientWidth) + "px"; 36 | // Hack to hide the scrollbar. 37 | if (completions.length <= 10) 38 | complete.style.width = (sel.clientWidth - 1) + "px"; 39 | 40 | var done = false; 41 | function close() { 42 | if (done) return; 43 | done = true; 44 | complete.parentNode.removeChild(complete); 45 | } 46 | function pick() { 47 | insert(completions[sel.selectedIndex]); 48 | close(); 49 | setTimeout(function(){editor.focus();}, 50); 50 | } 51 | CodeMirror.connect(sel, "blur", close); 52 | CodeMirror.connect(sel, "keydown", function(event) { 53 | var code = event.keyCode; 54 | // Enter 55 | if (code == 13) {CodeMirror.e_stop(event); pick();} 56 | // Escape 57 | else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();} 58 | else if (code != 38 && code != 40) { 59 | close(); editor.focus(); 60 | // Pass the event to the CodeMirror instance so that it can handle things like backspace properly. 61 | editor.triggerOnKeyDown(event); 62 | setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50); 63 | } 64 | }); 65 | CodeMirror.connect(sel, "dblclick", pick); 66 | 67 | sel.focus(); 68 | // Opera sometimes ignores focusing a freshly created node 69 | if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100); 70 | return true; 71 | }; 72 | })(); 73 | -------------------------------------------------------------------------------- /docs/vendor/cm/mode/javascript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodeMirror: JavaScript mode 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

CodeMirror: JavaScript mode

13 | 14 |
63 | 64 | 70 | 71 |

JavaScript mode supports a single configuration 72 | option, json, which will set the mode to expect JSON 73 | data rather than a JavaScript program.

74 | 75 |

MIME types defined: text/javascript, application/json.

76 | 77 | 78 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/blackboard.css: -------------------------------------------------------------------------------- 1 | /* Port of TextMate's Blackboard theme */ 2 | 3 | .cm-s-blackboard { background: #0C1021; color: #F8F8F8; } 4 | .cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; } 5 | .cm-s-blackboard .CodeMirror-gutter { background: #0C1021; border-right: 0; } 6 | .cm-s-blackboard .CodeMirror-gutter-text { color: #888; } 7 | .cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; } 8 | 9 | .cm-s-blackboard .cm-keyword { color: #FBDE2D; } 10 | .cm-s-blackboard .cm-atom { color: #D8FA3C; } 11 | .cm-s-blackboard .cm-number { color: #D8FA3C; } 12 | .cm-s-blackboard .cm-def { color: #8DA6CE; } 13 | .cm-s-blackboard .cm-variable { color: #FF6400; } 14 | .cm-s-blackboard .cm-operator { color: #FBDE2D;} 15 | .cm-s-blackboard .cm-comment { color: #AEAEAE; } 16 | .cm-s-blackboard .cm-string { color: #61CE3C; } 17 | .cm-s-blackboard .cm-string-2 { color: #61CE3C; } 18 | .cm-s-blackboard .cm-meta { color: #D8FA3C; } 19 | .cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; } 20 | .cm-s-blackboard .cm-builtin { color: #8DA6CE; } 21 | .cm-s-blackboard .cm-tag { color: #8DA6CE; } 22 | .cm-s-blackboard .cm-attribute { color: #8DA6CE; } 23 | .cm-s-blackboard .cm-header { color: #FF6400; } 24 | .cm-s-blackboard .cm-hr { color: #AEAEAE; } 25 | .cm-s-blackboard .cm-link { color: #8DA6CE; } 26 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/cobalt.css: -------------------------------------------------------------------------------- 1 | .cm-s-cobalt { background: #002240; color: white; } 2 | .cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; } 3 | .cm-s-cobalt .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; } 4 | .cm-s-cobalt .CodeMirror-gutter-text { color: #d0d0d0; } 5 | .cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; } 6 | 7 | .cm-s-cobalt span.cm-comment { color: #08f; } 8 | .cm-s-cobalt span.cm-atom { color: #845dc4; } 9 | .cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; } 10 | .cm-s-cobalt span.cm-keyword { color: #ffee80; } 11 | .cm-s-cobalt span.cm-string { color: #3ad900; } 12 | .cm-s-cobalt span.cm-meta { color: #ff9d00; } 13 | .cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; } 14 | .cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; } 15 | .cm-s-cobalt span.cm-error { color: #9d1e15; } 16 | .cm-s-cobalt span.cm-bracket { color: #d8d8d8; } 17 | .cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; } 18 | .cm-s-cobalt span.cm-link { color: #845dc4; } 19 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/eclipse.css: -------------------------------------------------------------------------------- 1 | .cm-s-eclipse span.cm-meta {color: #FF1717;} 2 | .cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } 3 | .cm-s-eclipse span.cm-atom {color: #219;} 4 | .cm-s-eclipse span.cm-number {color: #164;} 5 | .cm-s-eclipse span.cm-def {color: #00f;} 6 | .cm-s-eclipse span.cm-variable {color: black;} 7 | .cm-s-eclipse span.cm-variable-2 {color: #0000C0;} 8 | .cm-s-eclipse span.cm-variable-3 {color: #0000C0;} 9 | .cm-s-eclipse span.cm-property {color: black;} 10 | .cm-s-eclipse span.cm-operator {color: black;} 11 | .cm-s-eclipse span.cm-comment {color: #3F7F5F;} 12 | .cm-s-eclipse span.cm-string {color: #2A00FF;} 13 | .cm-s-eclipse span.cm-string-2 {color: #f50;} 14 | .cm-s-eclipse span.cm-error {color: #f00;} 15 | .cm-s-eclipse span.cm-qualifier {color: #555;} 16 | .cm-s-eclipse span.cm-builtin {color: #30a;} 17 | .cm-s-eclipse span.cm-bracket {color: #cc7;} 18 | .cm-s-eclipse span.cm-tag {color: #170;} 19 | .cm-s-eclipse span.cm-attribute {color: #00c;} 20 | .cm-s-eclipse span.cm-link {color: #219;} 21 | 22 | .cm-s-eclipse .CodeMirror-matchingbracket { 23 | border:1px solid grey; 24 | color:black !important;; 25 | } 26 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/elegant.css: -------------------------------------------------------------------------------- 1 | .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;} 2 | .cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;} 3 | .cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;} 4 | .cm-s-elegant span.cm-variable {color: black;} 5 | .cm-s-elegant span.cm-variable-2 {color: #b11;} 6 | .cm-s-elegant span.cm-qualifier {color: #555;} 7 | .cm-s-elegant span.cm-keyword {color: #730;} 8 | .cm-s-elegant span.cm-builtin {color: #30a;} 9 | .cm-s-elegant span.cm-error {background-color: #fdd;} 10 | .cm-s-elegant span.cm-link {color: #762;} 11 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/lesser-dark.css: -------------------------------------------------------------------------------- 1 | /* 2 | http://lesscss.org/ dark theme 3 | Ported to CodeMirror by Peter Kroon 4 | */ 5 | .CodeMirror{ 6 | line-height: 15px; 7 | } 8 | .cm-s-lesser-dark { 9 | font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Monaco', Courier, monospace !important; 10 | font-size:12px; 11 | } 12 | 13 | .cm-s-lesser-dark { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; } 14 | .cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/ 15 | .cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; } 16 | .cm-s-lesser-dark .CodeMirror-lines { margin-left:3px; margin-right:3px; }/*editable code holder*/ 17 | 18 | div.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ 19 | 20 | .cm-s-lesser-dark .CodeMirror-gutter { background: #262626; border-right:1px solid #aaa; padding-right:3px; min-width:2.5em; } 21 | .cm-s-lesser-dark .CodeMirror-gutter-text { color: #777; } 22 | 23 | .cm-s-lesser-dark span.cm-keyword { color: #599eff; } 24 | .cm-s-lesser-dark span.cm-atom { color: #C2B470; } 25 | .cm-s-lesser-dark span.cm-number { color: #B35E4D; } 26 | .cm-s-lesser-dark span.cm-def {color: white;} 27 | .cm-s-lesser-dark span.cm-variable { color:#D9BF8C; } 28 | .cm-s-lesser-dark span.cm-variable-2 { color: #669199; } 29 | .cm-s-lesser-dark span.cm-variable-3 { color: white; } 30 | .cm-s-lesser-dark span.cm-property {color: #92A75C;} 31 | .cm-s-lesser-dark span.cm-operator {color: #92A75C;} 32 | .cm-s-lesser-dark span.cm-comment { color: #666; } 33 | .cm-s-lesser-dark span.cm-string { color: #BCD279; } 34 | .cm-s-lesser-dark span.cm-string-2 {color: #f50;} 35 | .cm-s-lesser-dark span.cm-meta { color: #738C73; } 36 | .cm-s-lesser-dark span.cm-error { color: #9d1e15; } 37 | .cm-s-lesser-dark span.cm-qualifier {color: #555;} 38 | .cm-s-lesser-dark span.cm-builtin { color: #ff9e59; } 39 | .cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; } 40 | .cm-s-lesser-dark span.cm-tag { color: #669199; } 41 | .cm-s-lesser-dark span.cm-attribute {color: #00c;} 42 | .cm-s-lesser-dark span.cm-header {color: #a0a;} 43 | .cm-s-lesser-dark span.cm-quote {color: #090;} 44 | .cm-s-lesser-dark span.cm-hr {color: #999;} 45 | .cm-s-lesser-dark span.cm-link {color: #00c;} 46 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/monokai.css: -------------------------------------------------------------------------------- 1 | /* Based on Sublime Text's Monokai theme */ 2 | 3 | .cm-s-monokai {background: #272822; color: #f8f8f2;} 4 | .cm-s-monokai div.CodeMirror-selected {background: #49483E !important;} 5 | .cm-s-monokai .CodeMirror-gutter {background: #272822; border-right: 0px;} 6 | .cm-s-monokai .CodeMirror-gutter-text {color: #d0d0d0;} 7 | .cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;} 8 | 9 | .cm-s-monokai span.cm-comment {color: #75715e;} 10 | .cm-s-monokai span.cm-atom {color: #ae81ff;} 11 | .cm-s-monokai span.cm-number {color: #ae81ff;} 12 | 13 | .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;} 14 | .cm-s-monokai span.cm-keyword {color: #f92672;} 15 | .cm-s-monokai span.cm-string {color: #e6db74;} 16 | 17 | .cm-s-monokai span.cm-variable {color: #a6e22e;} 18 | .cm-s-monokai span.cm-variable-2 {color: #9effff;} 19 | .cm-s-monokai span.cm-def {color: #fd971f;} 20 | .cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;} 21 | .cm-s-monokai span.cm-bracket {color: #f8f8f2;} 22 | .cm-s-monokai span.cm-tag {color: #f92672;} 23 | .cm-s-monokai span.cm-link {color: #ae81ff;} 24 | 25 | .cm-s-monokai .CodeMirror-matchingbracket { 26 | text-decoration: underline; 27 | color: white !important; 28 | } 29 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/neat.css: -------------------------------------------------------------------------------- 1 | .cm-s-neat span.cm-comment { color: #a86; } 2 | .cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; } 3 | .cm-s-neat span.cm-string { color: #a22; } 4 | .cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; } 5 | .cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; } 6 | .cm-s-neat span.cm-variable { color: black; } 7 | .cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; } 8 | .cm-s-neat span.cm-meta {color: #555;} 9 | .cm-s-neat span.cm-link { color: #3a3; } 10 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/night.css: -------------------------------------------------------------------------------- 1 | /* Loosely based on the Midnight Textmate theme */ 2 | 3 | .cm-s-night { background: #0a001f; color: #f8f8f8; } 4 | .cm-s-night div.CodeMirror-selected { background: #a8f !important; } 5 | .cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; } 6 | .cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; } 7 | .cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; } 8 | 9 | .cm-s-night span.cm-comment { color: #6900a1; } 10 | .cm-s-night span.cm-atom { color: #845dc4; } 11 | .cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; } 12 | .cm-s-night span.cm-keyword { color: #599eff; } 13 | .cm-s-night span.cm-string { color: #37f14a; } 14 | .cm-s-night span.cm-meta { color: #7678e2; } 15 | .cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; } 16 | .cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; } 17 | .cm-s-night span.cm-error { color: #9d1e15; } 18 | .cm-s-night span.cm-bracket { color: #8da6ce; } 19 | .cm-s-night span.cm-comment { color: #6900a1; } 20 | .cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; } 21 | .cm-s-night span.cm-link { color: #845dc4; } 22 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/rubyblue.css: -------------------------------------------------------------------------------- 1 | .cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */ 2 | 3 | .cm-s-rubyblue { background: #112435; color: white; } 4 | .cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; } 5 | .cm-s-rubyblue .CodeMirror-gutter { background: #1F4661; border-right: 7px solid #3E7087; min-width:2.5em; } 6 | .cm-s-rubyblue .CodeMirror-gutter-text { color: white; } 7 | .cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; } 8 | 9 | .cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; } 10 | .cm-s-rubyblue span.cm-atom { color: #F4C20B; } 11 | .cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; } 12 | .cm-s-rubyblue span.cm-keyword { color: #F0F; } 13 | .cm-s-rubyblue span.cm-string { color: #F08047; } 14 | .cm-s-rubyblue span.cm-meta { color: #F0F; } 15 | .cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; } 16 | .cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; } 17 | .cm-s-rubyblue span.cm-error { color: #AF2018; } 18 | .cm-s-rubyblue span.cm-bracket { color: #F0F; } 19 | .cm-s-rubyblue span.cm-link { color: #F4C20B; } 20 | .cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; } 21 | .cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; } 22 | -------------------------------------------------------------------------------- /docs/vendor/cm/theme/xq-dark.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2011 by MarkLogic Corporation 3 | Author: Mike Brevoort 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | .cm-s-xq-dark { background: #0a001f; color: #f8f8f8; } 24 | .cm-s-xq-dark span.CodeMirror-selected { background: #a8f !important; } 25 | .cm-s-xq-dark .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; } 26 | .cm-s-xq-dark .CodeMirror-gutter-text { color: #f8f8f8; } 27 | .cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; } 28 | 29 | .cm-s-xq-dark span.cm-keyword {color: #FFBD40;} 30 | .cm-s-xq-dark span.cm-atom {color: #6C8CD5;} 31 | .cm-s-xq-dark span.cm-number {color: #164;} 32 | .cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;} 33 | .cm-s-xq-dark span.cm-variable {color: #FFF;} 34 | .cm-s-xq-dark span.cm-variable-2 {color: #EEE;} 35 | .cm-s-xq-dark span.cm-variable-3 {color: #DDD;} 36 | .cm-s-xq-dark span.cm-property {} 37 | .cm-s-xq-dark span.cm-operator {} 38 | .cm-s-xq-dark span.cm-comment {color: gray;} 39 | .cm-s-xq-dark span.cm-string {color: #9FEE00;} 40 | .cm-s-xq-dark span.cm-meta {color: yellow;} 41 | .cm-s-xq-dark span.cm-error {color: #f00;} 42 | .cm-s-xq-dark span.cm-qualifier {color: #FFF700;} 43 | .cm-s-xq-dark span.cm-builtin {color: #30a;} 44 | .cm-s-xq-dark span.cm-bracket {color: #cc7;} 45 | .cm-s-xq-dark span.cm-tag {color: #FFBD40;} 46 | .cm-s-xq-dark span.cm-attribute {color: #FFF700;} 47 | -------------------------------------------------------------------------------- /src/ljc.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | const NODE_JS = 1; 4 | const JS_SHELL = 2; 5 | const BROWSER = 3; 6 | 7 | var mode; 8 | if (typeof process !== "undefined") { 9 | mode = NODE_JS; 10 | // Install compiler as an extension for '.ljs' files that are loaded using the 11 | // |require| function. This is how mocha tests are executed. 12 | var fs = require('fs'); 13 | require.extensions['.ljs'] = function(module, filename) { 14 | var source = fs.readFileSync(filename, 'utf8'); 15 | return module._compile(compile(source, {filename: filename, memcheck: false}), filename); 16 | }; 17 | } else if (typeof snarf !== "undefined") { 18 | mode = JS_SHELL; 19 | } else { 20 | mode = BROWSER; 21 | } 22 | 23 | var util, esprima, escodegen, estransform, compiler; 24 | var argv; 25 | 26 | if (mode === NODE_JS) { 27 | util = require("./util.js"); 28 | esprima = require("./esprima.js"); 29 | escodegen = require("./escodegen.js"); 30 | estransform = require("./estransform.js"); 31 | compiler = require("./compiler.js"); 32 | 33 | snarf = require('fs').readFileSync; 34 | argv = process.argv.slice(2); 35 | print = console.log; 36 | quit = process.exit; 37 | } else if (mode === JS_SHELL) { 38 | load("./estransform.js"); 39 | load("./util.js"); 40 | load("./esprima.js"); 41 | load("./escodegen.js"); 42 | load("./compiler.js"); 43 | 44 | argv = this.arguments; 45 | } 46 | 47 | if (mode !== NODE_JS) { 48 | util = this.util; 49 | esprima = this.esprima; 50 | escodegen = this.escodegen; 51 | estransform = this.estransform; 52 | compiler = this.compiler; 53 | } 54 | 55 | const assert = util.assert; 56 | const lang = estransform.lang; 57 | const allFields = estransform.allFields; 58 | 59 | function pretty(node, indent) { 60 | if (typeof indent === "undefined") { 61 | indent = ""; 62 | } 63 | 64 | var s = ""; 65 | 66 | if (node instanceof Array) { 67 | for (var i = 0, j = node.length; i < j; i++) { 68 | s += pretty(node[i], indent); 69 | } 70 | return s; 71 | } 72 | 73 | s += indent + node.type; 74 | 75 | var spec = lang[node.type]; 76 | if (!spec) { 77 | s += " ???\n"; 78 | return s; 79 | } 80 | 81 | var fields = allFields(spec); 82 | var children = []; 83 | var values = []; 84 | // We do loc manually. 85 | fields.pop(); 86 | for (var i = 0, j = fields.length; i < j; i++) { 87 | var fname = fields[i]; 88 | if (fname.charAt(0) === "@") { 89 | fname = fname.substr(1); 90 | if (node[fname]) { 91 | children.push(pretty(node[fname], indent + " ")); 92 | } 93 | } else { 94 | if (typeof node[fname] !== "undefined") { 95 | values.push(node[fname]); 96 | } 97 | } 98 | } 99 | 100 | if (values.length) { 101 | s += " '" + values.join("' '") + "'"; 102 | } 103 | 104 | var loc = node.loc; 105 | if (loc) { 106 | s += (" (" + loc.start.line + ":" + loc.start.column + "-" + 107 | loc.end.line + ":" + loc.end.column + ")"); 108 | } 109 | 110 | s += "\n" + children.join(""); 111 | return s; 112 | } 113 | 114 | function cli() { 115 | var optparser = new util.OptParser([ 116 | ["a", "asmjs", "", "Compile as asm.js module"], 117 | ["m", "module-name", "", "Export asm module as this name"], 118 | ["e", "exported-funcs", "main", "Functions to export from the asm module (comma-delimited)"], 119 | ["E", "only-parse", false, "Only parse"], 120 | ["A", "emit-ast", false, "Do not generate JS, emit AST"], 121 | ["P", "pretty-print", false, "Pretty-print AST instead of emitting JSON (with -A)"], 122 | ["b", "bare", false, "Do not wrap in a module"], 123 | // ["l", "load-instead", false, "Emit load('memory') instead of require('memory')"], 124 | ["W", "warn", true, "Print warnings (enabled by default)"], 125 | ["Wconversion", null, false, "Print intra-integer and pointer conversion warnings"], 126 | ["0", "simple-log", false, "Log simple messages. No colors and snippets."], 127 | ["t", "trace", false, "Trace compiler execution"], 128 | ["o", "output", "", "Output file name"], 129 | // ["m", "memcheck", false, "Compile with memcheck instrumentation"], 130 | ["h", "help", false, "Print this message"], 131 | ["w", "nowarn", false, "Inhibit all warning messages"] 132 | ]); 133 | 134 | var p = optparser.parse(argv); 135 | if (!p) { 136 | quit(1); 137 | } 138 | 139 | var options = p.options; 140 | var files = p.rest; 141 | 142 | if (!files.length || options.help) { 143 | print("ljc: [option(s)] file"); 144 | print(optparser.usage()); 145 | quit(); 146 | } 147 | 148 | var filename = files[0]; 149 | var path = filename.split("/"); 150 | var basename = path.pop(); 151 | var dir = path.join("/"); 152 | basename = basename.substr(0, basename.lastIndexOf(".")) || basename; 153 | 154 | var source = snarf(filename); 155 | options.filename = filename; 156 | options.basename = basename; 157 | var code = compile(source, options); 158 | 159 | if (options["pretty-print"]) { 160 | print(pretty(code)); 161 | } else { 162 | // SpiderMonkey has no way to write to a file, but if we're on node we can 163 | // emit .js. 164 | if (options["output"] && mode === NODE_JS && !options["only-parse"]) { 165 | // var outname = (dir ? dir + "/" : "") + basename; 166 | // Don't overwrite the source file by mistake. 167 | if (options["output"] !== filename) { 168 | if (options["emit-ast"]) { 169 | require('fs').writeFileSync(options["output"], JSON.stringify(code, null, 2)); 170 | } else { 171 | // Escodegen doesn't emit a final newline for some reason, so add one. 172 | require('fs').writeFileSync(options["output"], code + "\n"); 173 | } 174 | } 175 | } else { 176 | print(code); 177 | } 178 | } 179 | } 180 | 181 | function compile(source, options) { 182 | // -W anything infers -W. 183 | for (var p in options) { 184 | if (p.charAt(0) === "W") { 185 | options.warn = true; 186 | break; 187 | } 188 | } 189 | 190 | if(options.nowarn) { 191 | options.warn = false; 192 | } 193 | 194 | var logger = new util.Logger("ljc", options.filename, source, options); 195 | var code; 196 | 197 | try { 198 | var node = esprima.parse(source, { loc: true, comment: true, range: true, tokens: true }); 199 | //node = escodegen.attachComments(node, node.comments, node.tokens); 200 | var types = null; 201 | 202 | for(var i=0; i>> 0, _) { 43 | viewSM[idx + i] |= mask; 44 | } 45 | } 46 | function clearFlag(idx, size, mask) { 47 | var _; 48 | for (var i = 0; i < size; _ = i, i = (i + 1 | 0) >>> 0, _) { 49 | viewSM[idx + i] &= ~mask; 50 | } 51 | } 52 | function isSet(bt, flag) { 53 | if (viewSM[bt] & flag) { 54 | return true; 55 | } else { 56 | return false; 57 | } 58 | } 59 | // (byte, uint, bool) -> unit 60 | function setAddressable(bt, size, on) { 61 | if (on) { 62 | setFlag(bt, size, FLAG_ACC >>> 0); 63 | } else { 64 | clearFlag(bt, size, FLAG_ACC >>> 0); 65 | } 66 | } 67 | // (byte) -> bool 68 | function isAddressable(bt) { 69 | return isSet(bt, FLAG_ACC); 70 | } 71 | // (byte, uint, bool) -> unit 72 | function setDefined(bt, size, on) { 73 | if (on) { 74 | setFlag(bt, size, FLAG_DEF >>> 0); 75 | } else { 76 | clearFlag(bt, size, FLAG_DEF >>> 0); 77 | } 78 | } 79 | // (byte) -> bool 80 | function isDefined(bt) { 81 | return isSet(bt, FLAG_DEF); 82 | } 83 | // (byte, bool) -> unit 84 | function setAlloc(bt, value) { 85 | if (value) { 86 | setFlag(bt, 1, FLAG_MAL >>> 0); 87 | memcheck.used[bt] = callstack.slice(0); 88 | } else { 89 | clearFlag(bt, 1, FLAG_MAL >>> 0); 90 | memcheck.used[bt] = undefined; 91 | } 92 | } 93 | // (byte) -> bool 94 | function isAlloc(bt) { 95 | return isSet(bt, FLAG_MAL); 96 | } 97 | // (str, str) -> unit 98 | function addError(kind, msg) { 99 | if (memcheck.errors[kind] === undefined) { 100 | memcheck.errors[kind] = []; 101 | } 102 | memcheck.errors[kind].push(msg); 103 | } 104 | function addDoubleFreeError(bt) { 105 | memcheck.errors.double_free.push({ 106 | membyte: bt, 107 | trace: callstack.slice(0) 108 | }); 109 | } 110 | function addBadAccessError(bt) { 111 | memcheck.errors.bad_access.push({ 112 | membyte: bt, 113 | trace: callstack.slice(0) 114 | }); 115 | } 116 | function addUndefinedError(bt) { 117 | memcheck.errors.undef_access.push({ 118 | membyte: bt, 119 | trace: callstack.slice(0) 120 | }); 121 | } 122 | // unit -> [byte*] 123 | function getBadAccesses() { 124 | return memcheck.errors.bad_access; 125 | } 126 | // unit -> [byte*] 127 | function getBadUndefined() { 128 | return memcheck.errors.undef_access; 129 | } 130 | // unit -> [byte*] 131 | function getBadFrees() { 132 | return memcheck.errors.double_free; 133 | } 134 | // unit -> [byte, [str]] 135 | function getLeaks() { 136 | return memcheck.used.map(function (val, idx) { 137 | if (val) { 138 | return { 139 | membyte: idx, 140 | trace: val 141 | }; 142 | } 143 | }).filter(function (val, idx) { 144 | if (val) { 145 | return val; 146 | } 147 | }); 148 | } 149 | var callstack = []; 150 | function call_push(name, fname, line, col) { 151 | callstack.push(name + ' (' + fname + '.ljs:' + line + ':' + col + ')'); 152 | } 153 | function call_pop() { 154 | callstack.pop(); 155 | } 156 | function call_reset(name, line, col) { 157 | var fn = name + ':' + line + ':' + col; 158 | var idx = callstack.lastIndexOf(fn); 159 | if (idx !== -1) { 160 | callstack = callstack.slice(0, idx + 1); 161 | } 162 | } 163 | function getCallstack() { 164 | return callstack; 165 | } 166 | // uint -> str 167 | function report(limit) { 168 | function fmtErrors(err) { 169 | var errors; 170 | if (limit >= 0) { 171 | errors = err.slice(0, limit); 172 | } else { 173 | errors = err; 174 | } 175 | return errors.map(function (val, idx) { 176 | var stack; 177 | if (val.trace.length === 0) { 178 | stack = 'at '; 179 | } else { 180 | stack = val.trace.reverse().join('\n\tat '); 181 | } 182 | return 'address ' + val.membyte + '\n\t' + stack; 183 | }).join('\n'); 184 | } 185 | var leaks = '== Memory Leaks ==\n' + fmtErrors(getLeaks()); 186 | var access = '== Access of unallocated memory ==\n' + fmtErrors(getBadAccesses()); 187 | var undef = '== Access of uninitialized memory ==\n' + fmtErrors(getBadUndefined()); 188 | var frees = '== Free of unallocated memory ==\n' + fmtErrors(getBadFrees()); 189 | return [ 190 | access, 191 | undef, 192 | frees, 193 | leaks 194 | ].join('\n\n'); 195 | } 196 | exports.setAddressable = setAddressable; 197 | exports.isAddressable = isAddressable; 198 | exports.setDefined = setDefined; 199 | exports.isDefined = isDefined; 200 | exports.setAlloc = setAlloc; 201 | exports.isAlloc = isAlloc; 202 | exports.addDoubleFreeError = addDoubleFreeError; 203 | exports.addBadAccessError = addBadAccessError; 204 | exports.addUndefinedError = addUndefinedError; 205 | exports.getBadAccesses = getBadAccesses; 206 | exports.getBadUndefined = getBadUndefined; 207 | exports.getBadFrees = getBadFrees; 208 | exports.getLeaks = getLeaks; 209 | exports.report = report; 210 | exports.reset = reset; 211 | exports.enabled = enabled; 212 | exports.memcheck_call_pop = call_pop; 213 | exports.memcheck_call_push = call_push; 214 | exports.memcheck_call_reset = call_reset; 215 | exports.getCallstack = getCallstack; 216 | }.call(this, typeof exports === 'undefined' ? memcheck = {} : exports)); 217 | -------------------------------------------------------------------------------- /src/memcheck.ljs: -------------------------------------------------------------------------------- 1 | extern undefined; 2 | extern print; 3 | extern console; 4 | extern snarf; 5 | extern process; 6 | extern newGlobal; 7 | extern setDebug; 8 | extern ArrayBuffer; 9 | extern Uint8Array; 10 | extern Uint32Array; 11 | 12 | let NODE_JS = 1; 13 | let JS_SHELL = 2; 14 | let BROWSER = 3; 15 | 16 | let enabled = false; 17 | 18 | 19 | let mode; 20 | if (typeof process !== "undefined") { 21 | mode = NODE_JS; 22 | } else if (typeof snarf !== "undefined") { 23 | mode = JS_SHELL; 24 | } else { 25 | mode = BROWSER; 26 | } 27 | 28 | let ck, root, dbg; 29 | if (mode === NODE_JS) { 30 | print = console.log; 31 | } 32 | 33 | let memcheck = {}; 34 | 35 | // The shadow memory (SM) is a typed array with a corresponding U1 36 | // view that holds a addresssable/defined flag (FLAG_ACC and FLAG_DEF) 37 | // for each byte of main memory. 38 | let u8 FLAG_ACC = 0x1; 39 | let u8 FLAG_DEF = 0x2; 40 | let u8 FLAG_MAL = 0x4 41 | 42 | let SM; 43 | let viewSM; 44 | 45 | function reset(memSize) { 46 | SM = new ArrayBuffer(memSize); 47 | viewSM = new Uint8Array(SM); 48 | exports.enabled = enabled = true; 49 | 50 | memcheck = { 51 | // {byte* => [str]} 52 | used: [], 53 | errors: { 54 | // [byte*] 55 | double_free: [], 56 | // [{membyte: byte*, trace: [str]] 57 | bad_access: [], 58 | // [{membyte: byte*, trace: [str]] 59 | undef_access: [] 60 | } 61 | }; 62 | } 63 | 64 | function setFlag(byte *idx, uint size, uint mask) { 65 | for (let uint i = 0; i < size; i++) { 66 | viewSM[idx + i] |= mask; 67 | } 68 | } 69 | 70 | function clearFlag(byte *idx, uint size, uint mask) { 71 | for (let uint i = 0; i < size; i++) { 72 | viewSM[idx + i] &= ~mask; 73 | } 74 | } 75 | 76 | function isSet(byte *bt, flag) { 77 | if(viewSM[bt] & flag) { 78 | return true; 79 | } else { 80 | return false; 81 | } 82 | } 83 | 84 | 85 | // (byte, uint, bool) -> unit 86 | function setAddressable(byte *bt, uint size, on) { 87 | if(on) { 88 | setFlag(bt, size, FLAG_ACC); 89 | } else { 90 | clearFlag(bt, size, FLAG_ACC); 91 | } 92 | } 93 | 94 | // (byte) -> bool 95 | function isAddressable(byte *bt) { 96 | return isSet(bt, FLAG_ACC); 97 | } 98 | 99 | // (byte, uint, bool) -> unit 100 | function setDefined(byte *bt, uint size, on) { 101 | if(on) { 102 | setFlag(bt, size, FLAG_DEF); 103 | } else { 104 | clearFlag(bt, size, FLAG_DEF); 105 | } 106 | } 107 | 108 | // (byte) -> bool 109 | function isDefined(byte *bt) { 110 | return isSet(bt, FLAG_DEF); 111 | } 112 | 113 | // (byte, bool) -> unit 114 | function setAlloc(byte *bt, value) { 115 | if(value) { 116 | setFlag(bt, 1, FLAG_MAL); 117 | memcheck.used[bt] = callstack.slice(0); 118 | } else { 119 | clearFlag(bt, 1, FLAG_MAL); 120 | memcheck.used[bt] = undefined; 121 | } 122 | } 123 | 124 | 125 | 126 | // (byte) -> bool 127 | function isAlloc(byte *bt) { 128 | return isSet(bt, FLAG_MAL); 129 | } 130 | 131 | 132 | // (str, str) -> unit 133 | function addError(kind, msg) { 134 | if(memcheck.errors[kind] === undefined) { 135 | memcheck.errors[kind] = []; 136 | } 137 | memcheck.errors[kind].push(msg); 138 | } 139 | 140 | function addDoubleFreeError(byte *bt) { 141 | memcheck.errors.double_free.push({membyte: bt, trace: callstack.slice(0)}); 142 | } 143 | 144 | function addBadAccessError(byte *bt) { 145 | memcheck.errors.bad_access.push({membyte: bt, trace: callstack.slice(0) }); 146 | } 147 | 148 | function addUndefinedError(byte *bt) { 149 | memcheck.errors.undef_access.push({membyte: bt, trace: callstack.slice(0)}); 150 | } 151 | 152 | // unit -> [byte*] 153 | function getBadAccesses() { 154 | return memcheck.errors.bad_access; 155 | } 156 | 157 | // unit -> [byte*] 158 | function getBadUndefined() { 159 | return memcheck.errors.undef_access; 160 | } 161 | 162 | // unit -> [byte*] 163 | function getBadFrees() { 164 | return memcheck.errors.double_free; 165 | } 166 | 167 | // unit -> [byte, [str]] 168 | function getLeaks() { 169 | return memcheck.used.map(function(val, idx) { 170 | if(val) { 171 | return {membyte: idx, trace: val}; 172 | } 173 | }).filter(function (val, idx) { 174 | if(val) { 175 | return val; 176 | } 177 | }); 178 | } 179 | 180 | let callstack = []; 181 | 182 | function call_push(name, fname, line, col) { 183 | callstack.push(name + " (" + fname + ".ljs:" + line + ":" + col + ")") 184 | } 185 | function call_pop() { 186 | callstack.pop() 187 | } 188 | 189 | function call_reset(name, line, col) { 190 | let fn = name + ":" + line + ":" + col; 191 | let idx = callstack.lastIndexOf(fn) 192 | if(idx !== -1) { 193 | callstack = callstack.slice(0, idx+1); 194 | } 195 | } 196 | 197 | function getCallstack() { 198 | return callstack; 199 | } 200 | 201 | // uint -> str 202 | function report(limit) { 203 | function fmtErrors(err) { 204 | let errors; 205 | if(limit >= 0) { 206 | errors = err.slice(0, limit); 207 | } else { 208 | errors = err; 209 | } 210 | return errors.map(function(val, idx) { 211 | let stack; 212 | if(val.trace.length === 0) { 213 | stack = "at "; 214 | } else { 215 | stack = val.trace.reverse().join("\n\tat "); 216 | } 217 | return "address " + val.membyte + "\n\t" + stack; 218 | }).join("\n") 219 | } 220 | 221 | let leaks = "== Memory Leaks ==\n" + fmtErrors(getLeaks()); 222 | let access = "== Access of unallocated memory ==\n" + fmtErrors(getBadAccesses()); 223 | let undef = "== Access of uninitialized memory ==\n" + fmtErrors(getBadUndefined()); 224 | let frees = "== Free of unallocated memory ==\n" + fmtErrors(getBadFrees()); 225 | return [access, undef, frees, leaks].join("\n\n"); 226 | } 227 | 228 | exports.setAddressable = setAddressable; 229 | exports.isAddressable = isAddressable; 230 | exports.setDefined = setDefined; 231 | exports.isDefined = isDefined; 232 | exports.setAlloc = setAlloc; 233 | exports.isAlloc = isAlloc; 234 | 235 | exports.addDoubleFreeError = addDoubleFreeError; 236 | exports.addBadAccessError = addBadAccessError; 237 | exports.addUndefinedError = addUndefinedError; 238 | 239 | exports.getBadAccesses = getBadAccesses; 240 | exports.getBadUndefined = getBadUndefined; 241 | exports.getBadFrees = getBadFrees; 242 | exports.getLeaks = getLeaks; 243 | 244 | exports.report = report; 245 | exports.reset = reset; 246 | exports.enabled = enabled; 247 | 248 | exports.memcheck_call_pop = call_pop; 249 | exports.memcheck_call_push = call_push; 250 | exports.memcheck_call_reset = call_reset; 251 | exports.getCallstack = getCallstack; 252 | -------------------------------------------------------------------------------- /src/modules.js: -------------------------------------------------------------------------------- 1 | var modules = {}; 2 | var modulesInstances = {}; 3 | 4 | function require(name) { 5 | // assert (name in modules, "Module \"" + name + "\" is not loaded."); 6 | var module = modulesInstances[name]; 7 | if (module) { 8 | return module; 9 | } 10 | return modulesInstances[name] = modules[name](); 11 | } -------------------------------------------------------------------------------- /src/pool.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | /** 3 | * We cannot store references to JavaScript objects in the LLJS heap. We need a way to 4 | * manage all the JS objects that enter the LLJS heap using some kind of reference counting 5 | * scheme, hence this reference counted object pool. 6 | * 7 | * Manages a reference counted pool of objects. It maintains a bi-directional mapping of 8 | * numeric IDs to Objects. Each object in the pool is given an unique ID that is stored 9 | * as a property in the object. The mapping from IDs to Objects is done using a dense 10 | * object array stored in the pool. 11 | * 12 | * The trick is to reuse objecet IDs so that the dense object map doesn't get too large. 13 | * This is done using a |bit| map that keeps track of available object IDs. Searching for 14 | * a new ID is done using a wrap-around linear scan through the bit map, starting at the 15 | * |nextWord| position which is updated whenever an ID is freed or found. 16 | * 17 | * The pool provides three functions: 18 | * 19 | * acquire (obj) adds the |obj| to the pool, increments the reference count and returns its ID. 20 | * release (obj) decrements the reference count and removes the object if the count is zero. 21 | * get (id) returns the object with the given |id|. 22 | * 23 | */ 24 | var Pool = function (initialSize) { 25 | var obj = []; 26 | /* ID to Object Map */ 27 | var ref; 28 | /* Reference Count Map */ 29 | var bit; 30 | /* Used ID Bit Map */ 31 | var size = 0; 32 | var resizeCount = 0; 33 | const MIN_SIZE = 1024; 34 | function resize(newSize) { 35 | var oldRef = ref; 36 | ref = new Uint16Array(newSize); 37 | if (oldRef) { 38 | ref.set(oldRef); 39 | } 40 | var oldBit = bit; 41 | bit = new Uint32Array(Math.ceil(newSize / 32)); 42 | if (oldBit) { 43 | bit.set(oldBit); 44 | } 45 | size = newSize; 46 | resizeCount++; 47 | } 48 | resize(Math.max(initialSize, MIN_SIZE)); 49 | /** 50 | * Tidy uses defineProperty to add IDs to objects when they are aquired and delete to 51 | * remove their IDs when they are released. This is slightly slower than leaving the 52 | * ID property behind. 53 | */ 54 | const tidy = false; 55 | const OBJECT_ID_NAME = 'OBJECT ID'; 56 | function bitCount(v) { 57 | v = v - (v >> 1 & 1431655765); 58 | v = (v & 858993459) + (v >> 2 & 858993459) | 0; 59 | return ((v + (v >> 4) & 252645135) * 16843009 | 0) >> 24; 60 | } 61 | /** 62 | * This is a clever bit hack that computes the first zero bit in a number. 63 | * 64 | * (http://skalkoto.blogspot.com/2008/01/bit-operations-find-first-zero-bit.html) 65 | * 66 | * v = 1010 1111 67 | * v = ~v = 0101 0000 (1) Invert the number. 68 | * -v = 1011 0000 (2) Compute 2's complement. 69 | * v = v & -v = 0001 0000 (3) And (1) and (2). 70 | * 71 | * The result is the bit position of the 1 bit in (3) which you can compute 72 | * by subtracting 1 and then counting bits. 73 | * 74 | * v - 1 = 0000 1111 4) Subtract 1, and use bitCount() to find the 75 | * result. 76 | * 77 | */ 78 | function firstZero(v) { 79 | v = ~v; 80 | v = (v & -v) - 1 | 0; 81 | // Inlined bitCount(v). 82 | v = v - (v >> 1 & 1431655765); 83 | v = (v & 858993459) + (v >> 2 & 858993459) | 0; 84 | return ((v + (v >> 4) & 252645135) * 16843009 | 0) >> 24; 85 | } 86 | var nextWord = 0; 87 | /** 88 | * Finds the next available ID by scanning the bit map. 89 | */ 90 | function nextID() { 91 | var cur = nextWord; 92 | var end = bit.length; 93 | while (true) { 94 | for (var i = cur, j = end; i < j; i++) { 95 | var word = bit[i]; 96 | if (word === 4294967295) { 97 | continue; 98 | } else if (word === 0) { 99 | bit[i] = 1; 100 | nextWord = i; 101 | return i << 5; 102 | } else { 103 | var fz = firstZero(word); 104 | bit[i] |= 1 << fz; 105 | nextWord = i; 106 | return (i << 5) + fz; 107 | } 108 | } 109 | if (end === nextWord) { 110 | /* Double the size if we can't find a free ID */ 111 | nextWord = size; 112 | resize(size * 2); 113 | return nextID(); 114 | } 115 | end = cur; 116 | cur = 0; 117 | } 118 | } 119 | /** 120 | * Frees an ID, by clearing a bit in the bit map. 121 | */ 122 | function freeID(id) { 123 | bit[id >> 5] &= ~(1 << (id & 31)); 124 | nextWord = id >> 5; 125 | } 126 | /** 127 | * Adds an object to the pool if it doesn't exist and increments its reference count by one. 128 | */ 129 | function acquire(o) { 130 | var id = o[OBJECT_ID_NAME]; 131 | if (id === undefined) { 132 | id = nextID(); 133 | if (tidy) { 134 | Object.defineProperty(o, OBJECT_ID_NAME, { 135 | value: id, 136 | writable: false, 137 | enumerable: false, 138 | configurable: true 139 | }); 140 | } else { 141 | o[OBJECT_ID_NAME] = id; 142 | } 143 | obj[id] = o; 144 | ref[id] = 1; 145 | } else { 146 | ref[id]++; 147 | } 148 | return id; 149 | } 150 | /** 151 | * Decrements an objects reference count by one, and removes it from the pool if 152 | * the reference count is zero. 153 | */ 154 | function release(o) { 155 | releaseByID(o[OBJECT_ID_NAME]); 156 | } 157 | function releaseByID(id) { 158 | if (id === undefined) { 159 | return; 160 | } 161 | if (--ref[id] === 0) { 162 | freeID(id); 163 | var o = obj[id]; 164 | obj[id] = null; 165 | if (tidy) { 166 | delete o[OBJECT_ID_NAME]; 167 | } else { 168 | o[OBJECT_ID_NAME] = undefined; 169 | } 170 | } 171 | } 172 | function get(id) { 173 | return obj[id]; 174 | } 175 | function trace() { 176 | function getSizeName(v) { 177 | var KB = 1024; 178 | var MB = 1024 * KB; 179 | if (v / MB > 1) { 180 | return (v / MB).toFixed(2) + ' M'; 181 | } else if (v / KB > 1) { 182 | return (v / KB).toFixed(2) + ' K'; 183 | } else { 184 | return v + ' '; 185 | } 186 | } 187 | trace(' ID Map: ' + getSizeName(bit.length * 4) + 'B'); 188 | trace(' Count Map: ' + getSizeName(ref.length * 2) + 'B'); 189 | trace(' Object Map: ' + obj.length); 190 | trace('Resize Count: ' + resizeCount); 191 | var count = 0; 192 | for (var i = 0; i < bit.length; i++) { 193 | count += bitCount(bit[i]); 194 | } 195 | trace('Object Map Density: ' + (count / (bit.length * 32) * 100).toFixed(2) + ' %'); 196 | } 197 | return { 198 | acquire: acquire, 199 | release: release, 200 | releaseByID: releaseByID, 201 | trace: trace, 202 | get: get 203 | }; 204 | }(1024); 205 | exports.acquire = Pool.acquire; 206 | exports.release = Pool.release; 207 | exports.releaseByID = Pool.releaseByID; 208 | exports.trace = Pool.trace; 209 | exports.get = Pool.get; 210 | }.call(this, typeof exports === 'undefined' ? pool = {} : exports)); 211 | -------------------------------------------------------------------------------- /src/pool.ljs: -------------------------------------------------------------------------------- 1 | extern Uint16Array; 2 | extern Uint32Array; 3 | extern Math; 4 | extern undefined; 5 | extern Object; 6 | 7 | /** 8 | * We cannot store references to JavaScript objects in the LLJS heap. We need a way to 9 | * manage all the JS objects that enter the LLJS heap using some kind of reference counting 10 | * scheme, hence this reference counted object pool. 11 | * 12 | * Manages a reference counted pool of objects. It maintains a bi-directional mapping of 13 | * numeric IDs to Objects. Each object in the pool is given an unique ID that is stored 14 | * as a property in the object. The mapping from IDs to Objects is done using a dense 15 | * object array stored in the pool. 16 | * 17 | * The trick is to reuse objecet IDs so that the dense object map doesn't get too large. 18 | * This is done using a |bit| map that keeps track of available object IDs. Searching for 19 | * a new ID is done using a wrap-around linear scan through the bit map, starting at the 20 | * |nextWord| position which is updated whenever an ID is freed or found. 21 | * 22 | * The pool provides three functions: 23 | * 24 | * acquire (obj) adds the |obj| to the pool, increments the reference count and returns its ID. 25 | * release (obj) decrements the reference count and removes the object if the count is zero. 26 | * get (id) returns the object with the given |id|. 27 | * 28 | */ 29 | 30 | let Pool = (function (initialSize) { 31 | 32 | let obj = []; /* ID to Object Map */ 33 | let ref; /* Reference Count Map */ 34 | let bit; /* Used ID Bit Map */ 35 | 36 | let size = 0; 37 | let resizeCount = 0; 38 | 39 | const MIN_SIZE = 1024; 40 | 41 | function resize(newSize) { 42 | let oldRef = ref; 43 | ref = new Uint16Array(newSize); 44 | if (oldRef) { 45 | ref.set(oldRef); 46 | } 47 | let oldBit = bit; 48 | bit = new Uint32Array(Math.ceil(newSize / 32)); 49 | if (oldBit) { 50 | bit.set(oldBit); 51 | } 52 | size = newSize; 53 | resizeCount ++; 54 | } 55 | 56 | resize(Math.max(initialSize, MIN_SIZE)); 57 | 58 | /** 59 | * Tidy uses defineProperty to add IDs to objects when they are aquired and delete to 60 | * remove their IDs when they are released. This is slightly slower than leaving the 61 | * ID property behind. 62 | */ 63 | const tidy = false; 64 | 65 | const OBJECT_ID_NAME = "OBJECT ID"; 66 | 67 | function bitCount(v) { 68 | v = v - ((v >> 1) & 0x55555555); 69 | v = (v & 0x33333333) + ((v >> 2) & 0x33333333); 70 | return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; 71 | } 72 | 73 | /** 74 | * This is a clever bit hack that computes the first zero bit in a number. 75 | * 76 | * (http://skalkoto.blogspot.com/2008/01/bit-operations-find-first-zero-bit.html) 77 | * 78 | * v = 1010 1111 79 | * v = ~v = 0101 0000 (1) Invert the number. 80 | * -v = 1011 0000 (2) Compute 2's complement. 81 | * v = v & -v = 0001 0000 (3) And (1) and (2). 82 | * 83 | * The result is the bit position of the 1 bit in (3) which you can compute 84 | * by subtracting 1 and then counting bits. 85 | * 86 | * v - 1 = 0000 1111 4) Subtract 1, and use bitCount() to find the 87 | * result. 88 | * 89 | */ 90 | function firstZero(v) { 91 | v = ~v; 92 | v = (v & (-v)) - 1; 93 | // Inlined bitCount(v). 94 | v = v - ((v >> 1) & 0x55555555); 95 | v = (v & 0x33333333) + ((v >> 2) & 0x33333333); 96 | return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; 97 | } 98 | 99 | let nextWord = 0; 100 | 101 | /** 102 | * Finds the next available ID by scanning the bit map. 103 | */ 104 | function nextID() { 105 | let cur = nextWord; 106 | let end = bit.length; 107 | while (true) { 108 | for (let i = cur, j = end; i < j; i++) { 109 | let word = bit[i]; 110 | if (word === 0xFFFFFFFF) { 111 | continue; 112 | } else if (word === 0) { 113 | bit[i] = 1; 114 | nextWord = i; 115 | return i << 5; 116 | } else { 117 | let fz = firstZero(word); 118 | bit[i] |= 1 << fz; 119 | nextWord = i; 120 | return (i << 5) + fz; 121 | } 122 | } 123 | if (end === nextWord) { 124 | /* Double the size if we can't find a free ID */ 125 | nextWord = size; 126 | resize(size * 2); 127 | return nextID(); 128 | } 129 | end = cur; 130 | cur = 0; 131 | } 132 | } 133 | 134 | /** 135 | * Frees an ID, by clearing a bit in the bit map. 136 | */ 137 | function freeID(id) { 138 | bit[id >> 5] &= ~(1 << (id & 0x1f)); 139 | nextWord = id >> 5; 140 | } 141 | 142 | /** 143 | * Adds an object to the pool if it doesn't exist and increments its reference count by one. 144 | */ 145 | function acquire(o) { 146 | let id = o[OBJECT_ID_NAME]; 147 | if (id === undefined) { 148 | id = nextID(); 149 | if (tidy) { 150 | Object.defineProperty(o, OBJECT_ID_NAME, { 151 | value : id, 152 | writable : false, 153 | enumerable : false, 154 | configurable : true 155 | }); 156 | } else { 157 | o[OBJECT_ID_NAME] = id; 158 | } 159 | obj[id] = o; 160 | ref[id] = 1; 161 | } else { 162 | ref[id] ++; 163 | } 164 | return id; 165 | } 166 | 167 | /** 168 | * Decrements an objects reference count by one, and removes it from the pool if 169 | * the reference count is zero. 170 | */ 171 | function release(o) { 172 | releaseByID(o[OBJECT_ID_NAME]); 173 | } 174 | 175 | function releaseByID(id) { 176 | if (id === undefined) { 177 | return; 178 | } 179 | if (--ref[id] === 0) { 180 | freeID(id); 181 | let o = obj[id]; 182 | obj[id] = null; 183 | if (tidy) { 184 | delete o[OBJECT_ID_NAME]; 185 | } else { 186 | o[OBJECT_ID_NAME] = undefined; 187 | } 188 | } 189 | } 190 | 191 | function get(id) { 192 | return obj[id]; 193 | } 194 | 195 | function trace() { 196 | 197 | function getSizeName(v) { 198 | let KB = 1024; 199 | let MB = 1024 * KB; 200 | 201 | if (v / MB > 1) { 202 | return (v / MB).toFixed(2) + " M"; 203 | } else if (v / KB > 1) { 204 | return (v / KB).toFixed(2) + " K"; 205 | } else { 206 | return v + " "; 207 | } 208 | } 209 | 210 | trace(" ID Map: " + getSizeName(bit.length * 4) + "B"); 211 | trace(" Count Map: " + getSizeName(ref.length * 2) + "B"); 212 | trace(" Object Map: " + obj.length); 213 | trace("Resize Count: " + resizeCount); 214 | 215 | let count = 0; 216 | for (let i = 0; i < bit.length; i++) { 217 | count += bitCount(bit[i]); 218 | } 219 | trace("Object Map Density: " + ((count / (bit.length * 32)) * 100).toFixed(2) + " %"); 220 | } 221 | 222 | return { 223 | acquire: acquire, 224 | release: release, 225 | releaseByID: releaseByID, 226 | trace: trace, 227 | get: get 228 | }; 229 | 230 | })(1024); 231 | 232 | exports.acquire = Pool.acquire; 233 | exports.release = Pool.release; 234 | exports.releaseByID = Pool.releaseByID; 235 | exports.trace = Pool.trace; 236 | exports.get = Pool.get; -------------------------------------------------------------------------------- /src/template/footer.js: -------------------------------------------------------------------------------- 1 | 2 | function memcpy(dest, src, num) { 3 | dest = dest|0; src = src|0; num = num|0; 4 | var ret = 0; 5 | ret = dest|0; 6 | if ((dest&3) == (src&3)) { 7 | while (dest & 3) { 8 | if ((num|0) == 0) return ret|0; 9 | U1[(dest)]=U1[(src)]; 10 | dest = (dest+1)|0; 11 | src = (src+1)|0; 12 | num = (num-1)|0; 13 | } 14 | while ((num|0) >= 4) { 15 | U4[((dest)>>2)]=U4[((src)>>2)]; 16 | dest = (dest+4)|0; 17 | src = (src+4)|0; 18 | num = (num-4)|0; 19 | } 20 | } 21 | while ((num|0) > 0) { 22 | U1[(dest)]=U1[(src)]; 23 | dest = (dest+1)|0; 24 | src = (src+1)|0; 25 | num = (num-1)|0; 26 | } 27 | return ret|0; 28 | } 29 | 30 | function memset(ptr, value, num) { 31 | ptr = ptr|0; value = value|0; num = num|0; 32 | var stop = 0, value4 = 0, stop4 = 0, unaligned = 0; 33 | stop = (ptr + num)|0; 34 | if ((num|0) >= 20) { 35 | // This is unaligned, but quite large, so work hard to get to aligned settings 36 | value = value & 0xff; 37 | unaligned = ptr & 3; 38 | value4 = value | (value << 8) | (value << 16) | (value << 24); 39 | stop4 = stop & ~3; 40 | if (unaligned) { 41 | unaligned = (ptr + 4 - unaligned)|0; 42 | while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num 43 | U1[(ptr)]=value; 44 | ptr = (ptr+1)|0; 45 | } 46 | } 47 | while ((ptr|0) < (stop4|0)) { 48 | U4[((ptr)>>2)]=value4; 49 | ptr = (ptr+4)|0; 50 | } 51 | } 52 | while ((ptr|0) < (stop|0)) { 53 | U1[(ptr)]=value; 54 | ptr = (ptr+1)|0; 55 | } 56 | } 57 | 58 | return { {% exports %} }; 59 | 60 | })({ Uint8Array: Uint8Array, 61 | Int8Array: Int8Array, 62 | Uint16Array: Uint16Array, 63 | Int16Array: Int16Array, 64 | Uint32Array: Uint32Array, 65 | Int32Array: Int32Array, 66 | Float32Array: Float32Array, 67 | Float64Array: Float64Array, 68 | Math: Math }, 69 | { {% externs %} 70 | HEAP_SIZE: HEAP_SIZE, 71 | STACK_SIZE: STACK_SIZE, 72 | TOTAL_SIZE: SIZE }, 73 | buffer); 74 | 75 | function assertEqual(val1, val2) { 76 | var err = true; 77 | var msg; 78 | if(val1 | 0 !== val1) { 79 | if(Math.abs(val1 - val2) < .00000001) { 80 | err = false; 81 | } 82 | else { 83 | msg = 'eps'; 84 | } 85 | } 86 | else if(val1 === val2) { 87 | err = false; 88 | } 89 | 90 | if(err) { 91 | throw new Error(val1 + ' does not equal ' + val2); 92 | } 93 | } 94 | 95 | function _print(/* arg1, arg2, ..., argN */) { 96 | var func = ((typeof console !== 'undefined' && console.log) || print); 97 | func.apply(null, arguments); 98 | } 99 | 100 | var _time; 101 | function start() { 102 | _time = Date.now(); 103 | } 104 | 105 | function end() { 106 | return Date.now() - _time; 107 | } 108 | 109 | {% finalize %} 110 | })(); 111 | -------------------------------------------------------------------------------- /src/template/header.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | if(!Math.imul) { 4 | Math.imul = function(x, y) { return x * y; }; 5 | } 6 | 7 | var MB = 1024 * 1024; 8 | var SIZE = 256 * MB; 9 | var STACK_SIZE = 2 * MB; 10 | var HEAP_SIZE = SIZE - STACK_SIZE; 11 | var buffer = new ArrayBuffer(SIZE); 12 | 13 | if(typeof window !== 'undefined') { 14 | window.U1 = new Uint8Array(buffer); 15 | window.I1 = new Int8Array(buffer); 16 | window.U2 = new Uint16Array(buffer); 17 | window.I2 = new Int16Array(buffer); 18 | window.U4 = new Uint32Array(buffer); 19 | window.I4 = new Int32Array(buffer); 20 | window.F4 = new Float32Array(buffer); 21 | window.F8 = new Float64Array(buffer); 22 | 23 | window.asmBuffer = buffer; 24 | } 25 | 26 | var asm = (function (global, env, buffer) { 27 | "use asm"; 28 | 29 | var stackSize = env.STACK_SIZE|0; 30 | var heapSize = env.HEAP_SIZE|0; 31 | var totalSize = env.TOTAL_SIZE|0; 32 | 33 | {% imports %} 34 | 35 | var U1 = new global.Uint8Array(buffer); 36 | var I1 = new global.Int8Array(buffer); 37 | var U2 = new global.Uint16Array(buffer); 38 | var I2 = new global.Int16Array(buffer); 39 | var U4 = new global.Uint32Array(buffer); 40 | var I4 = new global.Int32Array(buffer); 41 | var F4 = new global.Float32Array(buffer); 42 | var F8 = new global.Float64Array(buffer); 43 | 44 | var acos = global.Math.acos; 45 | var asin = global.Math.asin; 46 | var atan = global.Math.atan; 47 | var cos = global.Math.cos; 48 | var sin = global.Math.sin; 49 | var tan = global.Math.tan; 50 | var ceil = global.Math.ceil; 51 | var floor = global.Math.floor; 52 | var exp = global.Math.exp; 53 | var log = global.Math.log; 54 | var sqrt = global.Math.sqrt; 55 | var abs = global.Math.abs; 56 | var atan2 = global.Math.atan2; 57 | var pow = global.Math.pow; 58 | var imul = global.Math.imul; 59 | 60 | -------------------------------------------------------------------------------- /src/tests/structs-0.ljs: -------------------------------------------------------------------------------- 1 | extern Math; 2 | extern console; 3 | 4 | struct Point { 5 | int x, y; 6 | function Point (int x, int y) { 7 | this->x = x; 8 | this->y = y; 9 | } 10 | function toString() { 11 | return "{x: " + this->x + ", y: " + this->y + "}"; 12 | } 13 | function distanceTo(Point * other) { 14 | let Line l (this->x, this->y, other->x, other->y); 15 | console.info(l.toString()); 16 | return l.getLength(); 17 | } 18 | } 19 | 20 | struct Line { 21 | Point a, b; 22 | function Line (int x1, int y1, int x2, int y2) { 23 | this->a.x = x1; 24 | this->a.y = y1; 25 | this->b.x = x2; 26 | this->b.y = y2; 27 | } 28 | function float getLength() { 29 | let float dx = this->a.x - this->b.x; 30 | let float dy = this->a.y - this->b.y; 31 | return float(Math.sqrt(dx * dx + dy * dy)); 32 | } 33 | function toString() { 34 | return "{" + this->a.toString() + " -> " + this->b.toString() + "}"; 35 | } 36 | } 37 | 38 | union Box { 39 | int x; 40 | int y; 41 | function Box(int x, int y) { 42 | this->x = x; 43 | this->y = y; 44 | } 45 | function sum () { 46 | return this->x + this->y; 47 | } 48 | } 49 | 50 | let Box b (1, 2); 51 | console.info(b.sum()); 52 | 53 | let Point * p = new Point(1, 2); 54 | 55 | console.info(p->toString()); 56 | 57 | let Line * l = new Line(1, 2, 3, 4); 58 | 59 | console.info(l->toString()); 60 | console.info(l->getLength()); 61 | 62 | let Line l1 (1, 2, 3, 4), l2 (2, 3, 4, 5), *l3; 63 | 64 | console.info(l1.toString()); 65 | 66 | console.info(l1.a.toString()); 67 | console.info(l1.b.toString()); 68 | 69 | for (let int i = 0; i < 10; i++) { 70 | let Point * k = new Point(1, 2); 71 | console.info(k->toString()); 72 | console.info(k); 73 | } 74 | 75 | for (let int i = 0; i < 10; i++) { 76 | let Point a (i, 1), b (1, i); 77 | console.info(a.toString() + " @" + &a); 78 | console.info(b.toString() + " @" + &b); 79 | console.info(a.distanceTo(&b)); 80 | } -------------------------------------------------------------------------------- /src/tests/test-memcheck.ljs: -------------------------------------------------------------------------------- 1 | extern undefined; 2 | extern console; 3 | extern process; 4 | extern snarf; 5 | extern print; 6 | extern memory; 7 | extern assertEq; 8 | 9 | let NODE_JS = 1; 10 | let JS_SHELL = 2; 11 | let BROWSER = 3; 12 | 13 | 14 | struct Body { 15 | double x, y, mass; 16 | }; 17 | 18 | 19 | let mode; 20 | if (typeof process !== "undefined") { 21 | mode = NODE_JS; 22 | } else if (typeof snarf !== "undefined") { 23 | mode = JS_SHELL; 24 | } else { 25 | mode = BROWSER; 26 | } 27 | 28 | let m, assert, assertTrue; 29 | if (mode === NODE_JS) { 30 | m = require('memory'); 31 | print = console.log; 32 | assert = require('assert').strictEqual; 33 | assertTrue = require('assert').ok; 34 | } else { 35 | m = memory; 36 | //(load('memory.js'), memory); 37 | assert = assertEq; 38 | assertTrue = function(val) { assert(val, true); } 39 | } 40 | 41 | 42 | struct Node { 43 | u16 value; 44 | u16 other; 45 | }; 46 | 47 | // (byte, [{membyte: byte*}] -> bool 48 | function isIn(byte *x, l) { 49 | return l.some(function(el, idx) { 50 | return el.membyte === x; 51 | }); 52 | } 53 | 54 | let checker = m.memcheck; 55 | 56 | function test_access() { 57 | function badGetU8() { 58 | let u8 *x = new u8; 59 | *x = 5; 60 | let u8 *badp = x + 1; 61 | let u8 good = *x; 62 | let u8 bad = *badp; 63 | let errors = checker.getBadAccesses(); 64 | 65 | assert(1, errors.length, "only had one bad access"); 66 | 67 | assertTrue(isIn(badp, errors), 68 | "tried to get a unalloced u8 pointer"); 69 | let trace = errors[0].trace; 70 | assertTrue(trace[trace.length-1].indexOf("badGetU8") !== -1); 71 | } 72 | 73 | function badGetI8() { 74 | let i8 *x = new i8; 75 | *x = 5; 76 | let i8 *badp = x + 1; 77 | let i8 good = *x; 78 | let i8 bad = *badp; 79 | 80 | assert(1, checker.getBadAccesses().length, 81 | "only had one bad access"); 82 | assertTrue(isIn(badp, checker.getBadAccesses()), 83 | "tried to get a unalloced i8 pointer"); 84 | } 85 | 86 | function badGetU32() { 87 | let u32 *x = new int; 88 | *x = 5; 89 | let u32 *badp = x + 1; 90 | let u32 good = *x; 91 | let u32 bad = *badp; 92 | 93 | assert(1, checker.getBadAccesses().length, 94 | "only had one bad access"); 95 | assertTrue(isIn(badp, checker.getBadAccesses()), 96 | "tried to get a unalloced u32 pointer"); 97 | } 98 | 99 | function badGetMixed() { 100 | // warm up some allocs 101 | for(let uint i = 0; i < 100; i++) { 102 | let u32 *x = new u32; 103 | // leaking all over the places but we don't care 104 | } 105 | let u32 *good = new u32; 106 | let u32 *badp = good + 1; 107 | 108 | // bad dereference 109 | let u32 bad = *badp; 110 | 111 | assert(1, checker.getBadAccesses().length, 112 | "only had one bad access"); 113 | assertTrue(isIn(badp, checker.getBadAccesses()), 114 | "tried to get a unalloced u32 pointer"); 115 | } 116 | 117 | function badSet() { 118 | let int *badp; 119 | *badp = 4; 120 | assert(1, checker.getBadAccesses().length, 121 | "only had one bad access"); 122 | assertTrue(isIn(badp, checker.getBadAccesses()), 123 | "tried to set a unalloced int pointer"); 124 | } 125 | 126 | function getMultiple() { 127 | let u8 *x = new u8; 128 | let u8 *y = new u8; 129 | 130 | let u8 *badx = x + 1; 131 | let u8 *bady = y + 1; 132 | 133 | let u8 good = *x; 134 | good = *y; 135 | 136 | let u8 bad = *badx; 137 | bad = *bady 138 | 139 | assert(2, checker.getBadAccesses().length, 140 | "only had one bad access"); 141 | assertTrue(isIn(badx, checker.getBadAccesses()), 142 | "tried to get a unalloced u8 pointer"); 143 | assertTrue(isIn(bady, checker.getBadAccesses()), 144 | "tried to get a unalloced u8 pointer"); 145 | } 146 | 147 | function getAfterDelete() { 148 | let u8 *x = new u8; 149 | delete x; 150 | *x 151 | assert(1, checker.getBadAccesses().length, 152 | "only had one bad access"); 153 | assertTrue(isIn(x, checker.getBadAccesses()), 154 | "tried to get a unalloced u8 pointer"); 155 | } 156 | 157 | function getStruct() { 158 | let Body *b = new Body; 159 | 160 | b->x = 5; 161 | b->y = 10; 162 | b->mass = 100; 163 | 164 | assert(0, checker.getBadAccesses().length, 165 | "had no bad accesses"); 166 | } 167 | 168 | print("running bad access tests (gets/sets of unallocated memory)..."); 169 | 170 | m.reset(); 171 | badGetU8(); 172 | 173 | m.reset(); 174 | badGetI8(); 175 | 176 | m.reset(); 177 | badGetU32(); 178 | 179 | m.reset(); 180 | badGetMixed(); 181 | 182 | m.reset(); 183 | badSet(); 184 | 185 | m.reset(); 186 | getMultiple(); 187 | 188 | m.reset(); 189 | getAfterDelete(); 190 | 191 | m.reset(); 192 | getStruct(); 193 | 194 | print("passed"); 195 | m.reset(); 196 | } 197 | 198 | function test_undefined() { 199 | function undefU8() { 200 | let u8 *x = new u8; 201 | *x; 202 | 203 | let errors = checker.getBadUndefined(); 204 | 205 | assert(1, errors.length, 206 | "only had one bad access"); 207 | 208 | assertTrue(isIn(x, errors), 209 | "tried to get a undef u8 location"); 210 | let trace = errors[0].trace; 211 | assertTrue(trace[trace.length-1].indexOf("undefU8") !== -1); 212 | } 213 | 214 | function undefU32() { 215 | let u32 *x = new u32; 216 | *x; 217 | 218 | assert(1, checker.getBadUndefined().length, 219 | "only had one bad access"); 220 | assertTrue(isIn(x, checker.getBadUndefined()), 221 | "tried to get a undef u32 location"); 222 | } 223 | 224 | function undefMultiple() { 225 | let u32 *x = new u32; 226 | let u32 *y = new u32; 227 | *x; 228 | *y; 229 | 230 | assert(2, checker.getBadUndefined().length, 231 | "only had one bad access"); 232 | assertTrue(isIn(x, checker.getBadUndefined()), 233 | "tried to get a undef u32 location"); 234 | assertTrue(isIn(y, checker.getBadUndefined()), 235 | "tried to get a undef u32 location"); 236 | } 237 | 238 | // we are tracking undefined memory at the byte level 239 | function undefByte() { 240 | let u32 *x = new u32; 241 | let u8 *y = x; 242 | *y = 42; 243 | // can dereference both x and y now 244 | *y 245 | *x 246 | assert(0, checker.getBadUndefined().length, 247 | "nothing bad yet"); 248 | let u8 *z = y + 1; 249 | *z 250 | assert(1, checker.getBadUndefined().length, 251 | "now bad"); 252 | assertTrue(isIn(z, checker.getBadUndefined()), 253 | "tried to get a undef u8 location"); 254 | } 255 | 256 | print("running undefined tests (gets of allocated but undefined memory)..."); 257 | 258 | m.reset(); 259 | undefU8(); 260 | 261 | m.reset(); 262 | undefU32(); 263 | 264 | m.reset(); 265 | undefMultiple(); 266 | 267 | m.reset(); 268 | undefByte(); 269 | 270 | print("passed"); 271 | m.reset(); 272 | } 273 | 274 | function test_frees() { 275 | function badFree() { 276 | let u32 *x; 277 | delete x; 278 | 279 | assert(1, checker.getBadFrees().length, 280 | "only had one bad access"); 281 | assertTrue(isIn(x, checker.getBadFrees()), 282 | "tried to free unalloced memory"); 283 | let trace = checker.getBadFrees()[0].trace; 284 | assertTrue(trace[trace.length-1].indexOf("badFree") !== -1); 285 | } 286 | 287 | function doubleFree() { 288 | let u32 *x = new u32; 289 | delete x; 290 | delete x; 291 | 292 | assert(1, checker.getBadFrees().length, 293 | "only had one bad access"); 294 | assertTrue(isIn(x, checker.getBadFrees()), 295 | "tried to double free"); 296 | } 297 | 298 | print("running free tests (double frees, or general frees of unalloced memory)..."); 299 | 300 | m.reset(); 301 | badFree(); 302 | 303 | m.reset(); 304 | doubleFree(); 305 | 306 | print("passed"); 307 | m.reset(); 308 | } 309 | 310 | 311 | function test_leak() { 312 | function int leak() { 313 | let int *x = new int; 314 | 315 | assert(checker.getLeaks().length, 1, 316 | "only had one leak "); 317 | assert((byte *) (x), checker.getLeaks()[0].membyte, 318 | "leaked an int"); 319 | let trace = checker.getLeaks()[0].trace; 320 | assertTrue(trace[trace.length-1].indexOf("leak") !== -1); 321 | } 322 | 323 | function leakLoop() { 324 | let u8 *x = new u8; 325 | for(let int i = 0; i < 99; i++) { 326 | x = new u8; 327 | } 328 | 329 | assert(100, checker.getLeaks().length, 330 | "had one hundred leaks"); 331 | } 332 | 333 | print("running leak tests (forgot to call delete)..."); 334 | 335 | m.reset(); 336 | leak(); 337 | 338 | m.reset(); 339 | leakLoop(); 340 | 341 | print("passed"); 342 | m.reset(); 343 | } 344 | 345 | function test_callstack() { 346 | function a() { 347 | b(); 348 | } 349 | function b() { 350 | throw "error!" 351 | } 352 | 353 | try { 354 | a(); 355 | } catch (e) { 356 | let uint *x; 357 | *x; 358 | 359 | let errors = checker.getBadAccesses(); 360 | assert(1, errors.length, "only had one bad access"); 361 | assertTrue(errors[0].trace[0].indexOf("test_callstack") !== -1, 362 | "this function should be on the top of the callstack") 363 | print("passed") 364 | } 365 | 366 | } 367 | 368 | test_access(); 369 | test_undefined(); 370 | test_frees(); 371 | test_leak(); 372 | 373 | test_callstack(); 374 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | /** 3 | * Types. 4 | */ 5 | 6 | function tystr(type, lvl) { 7 | return type ? type.toString(lvl) : "dyn"; 8 | } 9 | 10 | function TypeAlias(name) { 11 | this.name = name; 12 | }; 13 | 14 | function PrimitiveType(name, size, defaultValue, signed) { 15 | this.name = name; 16 | this.size = size; 17 | this.signed = signed; 18 | this.defaultValue = defaultValue; 19 | this.align = this; 20 | }; 21 | 22 | PrimitiveType.prototype.toString = function () { 23 | return this.name; 24 | }; 25 | 26 | PrimitiveType.prototype.lint = function () {}; 27 | 28 | function StructType(name) { 29 | this.name = name; 30 | this.members = []; 31 | this.fields = []; 32 | this.offset = 0; 33 | this.isUnion = false; 34 | this.staticType = this instanceof StructStaticType ? 35 | this : new StructStaticType(this); 36 | } 37 | 38 | StructType.prototype.toString = function (lvl) { 39 | lvl = lvl || 0; 40 | if (lvl > 0) { 41 | return this.name || ""; 42 | } 43 | var s = "struct" + (this.name ? (" " + this.name) : " ") + " { "; 44 | s += this.fields.map(function (f) { 45 | return tystr(f.type, lvl + 1) + " " + f.name; 46 | }).join("; "); 47 | return s + " }"; 48 | }; 49 | 50 | StructType.prototype.getMember = function getMember(name) { 51 | var members = this.members; 52 | for (var i = 0; i < members.length; i++) { 53 | if (members[i].name === name) { 54 | return members[i]; 55 | } 56 | } 57 | return null; 58 | }; 59 | 60 | function StructStaticType(type) { 61 | this.instanceType = type; 62 | StructType.call(this, type.name + "_Static"); 63 | } 64 | 65 | StructStaticType.prototype = Object.create(StructType.prototype); 66 | 67 | function PointerType(base) { 68 | this.base = base; 69 | } 70 | 71 | PointerType.prototype.defaultValue = 0; 72 | PointerType.prototype.size = 4; 73 | 74 | PointerType.prototype.toString = function (lvl) { 75 | lvl = lvl || 0; 76 | return tystr(this.base, lvl + 1) + "*"; 77 | }; 78 | 79 | function ArrayType(base, length) { 80 | PointerType.call(this, base); 81 | this.length = length; 82 | } 83 | 84 | ArrayType.prototype = Object.create(PointerType.prototype); 85 | ArrayType.prototype.toString = function (lvl) { 86 | lvl = lvl || 0; 87 | var lengths = ""; 88 | var base = this; 89 | while (base instanceof ArrayType) { 90 | lengths += '[' + (base.length !== undefined ? base.length : "*") + ']'; 91 | base = base.base; 92 | } 93 | return tystr(base, lvl + 1) + lengths; 94 | }; 95 | /** 96 | * Gets the root element type. 97 | */ 98 | ArrayType.prototype.getRoot = function () { 99 | var base = this; 100 | while (base instanceof ArrayType) { 101 | base = base.base; 102 | } 103 | return base; 104 | }; 105 | ArrayType.prototype.defaultValue = undefined; 106 | 107 | function ArrowType(paramTypes, returnType) { 108 | this.paramTypes = paramTypes; 109 | this.returnType = returnType; 110 | } 111 | 112 | ArrowType.prototype.toString = function () { 113 | return tystr(this.returnType, 0) + "(" + this.paramTypes.map(function (pty) { 114 | return tystr(pty, 0); 115 | }).join(", ") + ")"; 116 | }; 117 | 118 | const u8ty = new PrimitiveType("u8", 1, 0, false); 119 | const i8ty = new PrimitiveType("i8", 1, 0, true); 120 | const u16ty = new PrimitiveType("u16", 2, 0, false); 121 | const i16ty = new PrimitiveType("i16", 2, 0, true); 122 | const u32ty = new PrimitiveType("u32", 4, 0, false); 123 | const i32ty = new PrimitiveType("i32", 4, 0, true); 124 | const f32ty = new PrimitiveType("f32", 4, 0, undefined); 125 | const f64ty = new PrimitiveType("f64", 8, 0, undefined); 126 | 127 | const wordTy = u32ty; 128 | const voidTy = new PrimitiveType("void", 0, 0, undefined); 129 | const nullTy = new PrimitiveType("null", 0, 0, undefined); 130 | const bytePointerTy = new PointerType(u8ty); 131 | const spTy = new PointerType(u32ty); 132 | 133 | const mallocTy = new ArrowType([u32ty], bytePointerTy); 134 | const freeTy = new ArrowType([bytePointerTy], voidTy); 135 | 136 | function createMemcpyType(pointerTy) { 137 | return new ArrowType([pointerTy, pointerTy, u32ty], pointerTy); 138 | } 139 | 140 | function createMemsetType(pointerTy) { 141 | return new ArrowType([pointerTy, pointerTy.base, u32ty], voidTy); 142 | } 143 | 144 | const memcpyTy = createMemcpyType(bytePointerTy); 145 | // const memcpy2Ty = createMemcpyType(new PointerType(u16ty)); 146 | // const memcpy4Ty = createMemcpyType(new PointerType(u32ty)); 147 | const memsetTy = createMemsetType(bytePointerTy); 148 | // const memset2Ty = createMemsetType(new PointerType(u16ty)); 149 | // const memset4Ty = createMemsetType(new PointerType(u32ty)); 150 | 151 | u8ty.integral = u8ty.numeric = true; 152 | i8ty.integral = i8ty.numeric = true; 153 | u16ty.integral = u16ty.numeric = true; 154 | i16ty.integral = i16ty.numeric = true; 155 | u32ty.integral = u32ty.numeric = true; 156 | i32ty.integral = i32ty.numeric = true; 157 | f32ty.numeric = true; 158 | f64ty.numeric = true; 159 | 160 | var builtinTypes = { 161 | u8: u8ty, 162 | i8: i8ty, 163 | u16: u16ty, 164 | i16: i16ty, 165 | u32: u32ty, 166 | i32: i32ty, 167 | f32: f32ty, 168 | f64: f64ty, 169 | 170 | num: f64ty, 171 | int: i32ty, 172 | uint: u32ty, 173 | bool: i32ty, 174 | float: f32ty, 175 | double: f64ty, 176 | 177 | byte: u8ty, 178 | word: u32ty, 179 | 180 | void: voidTy, 181 | null: nullTy, 182 | dyn: undefined 183 | }; 184 | 185 | PointerType.prototype.align = u32ty; 186 | 187 | exports.TypeAlias = TypeAlias; 188 | exports.PrimitiveType = PrimitiveType; 189 | exports.StructType = StructType; 190 | exports.StructStaticType = StructStaticType; 191 | exports.PointerType = PointerType; 192 | exports.ArrayType = ArrayType; 193 | exports.ArrowType = ArrowType; 194 | exports.builtinTypes = builtinTypes; 195 | 196 | exports.tystr = tystr; 197 | 198 | exports.u8ty = u8ty; 199 | exports.i8ty = i8ty; 200 | exports.u16ty = u16ty; 201 | exports.i16ty = i16ty; 202 | exports.u32ty = u32ty; 203 | exports.i32ty = i32ty; 204 | exports.f32ty = f32ty; 205 | exports.f64ty = f64ty; 206 | 207 | exports.wordTy = wordTy; 208 | exports.voidTy = voidTy; 209 | exports.nullTy = nullTy; 210 | exports.bytePointerTy = bytePointerTy; 211 | exports.spTy = spTy; 212 | 213 | exports.mallocTy = mallocTy; 214 | exports.freeTy = freeTy; 215 | 216 | exports.memsetTy = memsetTy; 217 | // exports.memset2Ty = memset2Ty; 218 | // exports.memset4Ty = memset4Ty; 219 | 220 | exports.memcpyTy = memcpyTy; 221 | // exports.memcpy2Ty = memcpy2Ty; 222 | // exports.memcpy4Ty = memcpy4Ty; 223 | 224 | }).call(this, typeof exports === "undefined" ? (Types = {}) : exports); 225 | -------------------------------------------------------------------------------- /test/arrays-stack.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it; 4 | 5 | struct ST { 6 | int x; 7 | }; 8 | 9 | struct InlineArrayST { 10 | int arr[100]; 11 | }; 12 | 13 | struct InlineStructArrayST { 14 | InlineArrayST arr[100]; 15 | }; 16 | 17 | describe('Arrays-Stack', function () { 18 | it('allocates an int array on the stack', function () { 19 | let int arr[100]; 20 | arr[0] = 5; 21 | arr[1] = 10; 22 | 23 | assert (*arr === 5); 24 | assert (arr[0] === 5); 25 | assert (arr[1] === 10); 26 | let ST s; 27 | assert (&s - arr === 100); 28 | }); 29 | 30 | it('allocates an u8 array on the stack', function () { 31 | let u8 arr[100]; 32 | arr[2] = 5; 33 | assert (arr[2] === 5); 34 | }); 35 | 36 | it('allocates an u8 array on the stack', function () { 37 | let u8 arr[100]; 38 | arr[0] = 5; 39 | arr[1] = 10; 40 | assert (*arr === 5); 41 | assert (arr[0] === 5); 42 | assert (arr[1] === 10); 43 | 44 | let float arr2[100]; 45 | arr2[0] = 5; 46 | arr2[1] = 10; 47 | assert (*arr2 === 5); 48 | assert (arr2[0] === 5); 49 | assert (arr2[1] === 10); 50 | 51 | let ST s; 52 | assert (&s - (ST *)(arr) === 126); 53 | }); 54 | 55 | it('allocates a struct with an inline array', function () { 56 | let InlineArrayST s; 57 | s.arr[5] = 10; 58 | 59 | let ST s2; 60 | assert (&s2 - (ST *)(&s) === 100); 61 | }); 62 | 63 | it('allocates a struct with an inline array of structs with arrays', function () { 64 | let InlineStructArrayST s; 65 | s.arr[5].arr[5] = 5; 66 | 67 | let ST s2; 68 | assert (&s2 - (ST *)(&s) === 100 * 100); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /test/arrays.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it, console; 4 | 5 | describe('Arrays', function() { 6 | function testElements(int * a, int length) { 7 | for (let int i = 0; i < length; i++) { 8 | a[i] = i; 9 | } 10 | let int sum = 0; 11 | for (let int i = 0; i < length; i++) { 12 | sum += a[i]; 13 | } 14 | assert (sum === ((length * (length - 1)) / 2)); 15 | } 16 | 17 | it('Read / Write from i32 Heap Array', function () { 18 | testElements(new int [1024], 1024); 19 | }); 20 | 21 | it('Read / Write from i32 Stack Array', function () { 22 | let int a [1024]; 23 | testElements(a, 1024); 24 | }); 25 | }); 26 | 27 | describe('Stack Arrays', function() { 28 | it('u8', function () { 29 | let u8 a [1024]; 30 | a[42] = 42; 31 | assert (a[42] === 42); 32 | assert (*(a + 42) === 42); 33 | a[42] = 0xFFAD; 34 | assert (*(a + 42) === 0xAD); 35 | a[12] = -1; 36 | assert (a[12] === 255); 37 | }); 38 | 39 | it('i8', function () { 40 | let i8 a [1024]; 41 | a[42] = -42; 42 | assert (a[42] === -42); 43 | assert (*(a + 42) === -42); 44 | *(a + 42) = 0xFFAE; 45 | assert (*(a + 42) === -82); 46 | a[12] = -1; 47 | assert (a[12] === -1); 48 | }); 49 | 50 | it('1D Array with Initializer', function () { 51 | let int a [4] = [1, 2, 3, 4]; 52 | assert (a[0] === 1); 53 | assert (a[1] === 2); 54 | assert (a[2] === 3); 55 | assert (a[3] === 4); 56 | }); 57 | 58 | it('2D Array with Initializer', function () { 59 | let int a [2][2] = [[1, 2], [3, 4]]; 60 | assert (a[0][0] === 1); 61 | assert (a[0][1] === 2); 62 | assert (a[1][0] === 3); 63 | assert (a[1][1] === 4); 64 | }); 65 | 66 | it('5D Array', function () { 67 | let int a [5][5][5][5][5]; 68 | let int x = 0; 69 | for (let int i = 0; i < 5; i++) { 70 | for (let int j = 0; j < 5; j++) { 71 | for (let int k = 0; k < 5; k++) { 72 | for (let int l = 0; l < 5; l++) { 73 | for (let int m = 0; m < 5; m++) { 74 | a[i][j][k][l][m] = x++; 75 | } 76 | } 77 | } 78 | } 79 | } 80 | x = 0; 81 | for (let int i = 0; i < 5; i++) { 82 | for (let int j = 0; j < 5; j++) { 83 | for (let int k = 0; k < 5; k++) { 84 | for (let int l = 0; l < 5; l++) { 85 | for (let int m = 0; m < 5; m++) { 86 | assert (a[i][j][k][l][m] === x++); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | }); 93 | }); -------------------------------------------------------------------------------- /test/asm/bench.c: -------------------------------------------------------------------------------- 1 | 2 | int run() { 3 | int N = 200; 4 | int M = 700; 5 | unsigned int f = 0; 6 | unsigned short s = 0; 7 | int i, t; 8 | 9 | for(t = 0; t < M; t++) { 10 | for(i = 0; i < N; i++) { 11 | f = f + i / ((t % 5) + 1); 12 | if(f > 1000) f = f / ((t % 3) + 1); 13 | if(i % 4 == 0) f = f + i * (i % 8 == 0 ? 1 : -1); 14 | s = s + f*f % 256; 15 | } 16 | } 17 | 18 | return f; 19 | } 20 | 21 | int main() { 22 | unsigned int f; 23 | int i; 24 | 25 | for(i = 0; i < 1000; i++) { 26 | f = run(); 27 | } 28 | 29 | // Needed so that gcc doesn't remove the code as dead 30 | printf("%d", f); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/asm/bench.js: -------------------------------------------------------------------------------- 1 | 2 | if(!Math.imul) { 3 | Math.imul = function(x, y) { return x * y; }; 4 | } 5 | 6 | var MB = 1024 * 1024; 7 | var SIZE = 256 * MB; 8 | var STACK_SIZE = 2 * MB; 9 | var HEAP_SIZE = SIZE - STACK_SIZE; 10 | var buffer = new ArrayBuffer(SIZE); 11 | 12 | var asm = (function (global, env, buffer) { 13 | "use asm"; 14 | 15 | var stackSize = env.STACK_SIZE|0; 16 | var heapSize = env.HEAP_SIZE|0; 17 | var totalSize = env.TOTAL_SIZE|0; 18 | var assertEqual = env.assertEqual; 19 | var print = env.print; 20 | var start = env.start; 21 | var end = env.end; 22 | 23 | var U1 = new global.Uint8Array(buffer); 24 | var I1 = new global.Int8Array(buffer); 25 | var U2 = new global.Uint16Array(buffer); 26 | var I2 = new global.Int16Array(buffer); 27 | var U4 = new global.Uint32Array(buffer); 28 | var I4 = new global.Int32Array(buffer); 29 | var F4 = new global.Float32Array(buffer); 30 | var F8 = new global.Float64Array(buffer); 31 | 32 | var acos = global.Math.acos; 33 | var asin = global.Math.asin; 34 | var atan = global.Math.atan; 35 | var cos = global.Math.cos; 36 | var sin = global.Math.sin; 37 | var tan = global.Math.tan; 38 | var ceil = global.Math.ceil; 39 | var floor = global.Math.floor; 40 | var exp = global.Math.exp; 41 | var log = global.Math.log; 42 | var sqrt = global.Math.sqrt; 43 | var abs = global.Math.abs; 44 | var atan2 = global.Math.atan2; 45 | var pow = global.Math.pow; 46 | var imul = global.Math.imul; 47 | 48 | function run() { 49 | var N = 0, M = 0, f = 0, s = 0, t = 0, i = 0, $SP = 0; 50 | N = 200; 51 | M = 700; 52 | f = 0; 53 | s = 0; 54 | for (t = 0; (t | 0) < (M | 0); t = (t | 0) + 1 | 0) { 55 | for (i = 0; (i | 0) < (N | 0); i = (i | 0) + 1 | 0) { 56 | f = ((f >>> 0) + ((i | 0) / (((t | 0) % 5 | 0 | 0) + 1 | 0 | 0) | 0 | 0) | 0) >>> 0; 57 | if (f >>> 0 > 1000) 58 | f = ((f >>> 0) / ((((t | 0) % 3 | 0 | 0) + 1 | 0) >>> 0 >>> 0) | 0) >>> 0; 59 | if (((i | 0) % 4 | 0 | 0) == 0) 60 | f = ((f >>> 0) + (imul(i, ((i | 0) % 8 | 0 | 0) == 0 ? 1 : -1) | 0) | 0) >>> 0; 61 | s = ((s >>> 0) + ((imul(f & 65535, f & 65535) | 0) % 256 | 0 | 0) | 0) & 65535; 62 | } 63 | } 64 | } 65 | function main() { 66 | var _ = 0, i = 0, $SP = 0; 67 | U4[1] = totalSize; 68 | U4[0] = 4; 69 | start(); 70 | for (i = 0; (i | 0) < 1000; _ = i, i = (i | 0) + 1 | 0, _) { 71 | run(); 72 | } 73 | print(end() | 0); 74 | } 75 | 76 | return { main: main }; 77 | 78 | })({ Uint8Array: Uint8Array, 79 | Int8Array: Int8Array, 80 | Uint16Array: Uint16Array, 81 | Int16Array: Int16Array, 82 | Uint32Array: Uint32Array, 83 | Int32Array: Int32Array, 84 | Float32Array: Float32Array, 85 | Float64Array: Float64Array, 86 | Math: Math }, 87 | { HEAP_SIZE: HEAP_SIZE, 88 | STACK_SIZE: STACK_SIZE, 89 | TOTAL_SIZE: SIZE, 90 | assertEqual: assertEqual, 91 | print: _print, 92 | start: start, 93 | end: end }, 94 | buffer); 95 | 96 | 97 | function assertEqual(val1, val2) { 98 | var err = true; 99 | var msg; 100 | if(val1 | 0 !== val1) { 101 | if(Math.abs(val1 - val2) < .00000001) { 102 | err = false; 103 | } 104 | else { 105 | msg = 'eps'; 106 | } 107 | } 108 | else if(val1 === val2) { 109 | err = false; 110 | } 111 | 112 | if(err) { 113 | throw new Error(val1 + ' does not equal ' + val2); 114 | } 115 | } 116 | 117 | function _print(/* arg1, arg2, ..., argN */) { 118 | var func = ((typeof console !== 'undefined' && console.log) || print); 119 | func.apply(null, arguments); 120 | } 121 | 122 | var _time; 123 | function start() { 124 | _time = Date.now(); 125 | } 126 | 127 | function end() { 128 | return Date.now() - _time; 129 | } 130 | 131 | asm.main(); 132 | -------------------------------------------------------------------------------- /test/asm/bench.ljs: -------------------------------------------------------------------------------- 1 | 2 | extern start; 3 | extern end; 4 | extern print; 5 | 6 | function void run() { 7 | let int N = 200; 8 | let int M = 700; 9 | let uint f = 0; 10 | let u16 s = 0; 11 | 12 | let int t; 13 | let int i; 14 | 15 | for(t = 0; t < M; t = t + 1) { 16 | for(i = 0; i < N; i = i + 1) { 17 | f = f + i / ((t % 5) + 1); 18 | if(f > 1000) f = f / uint((t % 3) + 1); 19 | if(i % 4 == 0) f = f + i * (i % 8 == 0 ? 1 : -1); 20 | s = s + u16(f) * u16(f) % 256; 21 | } 22 | } 23 | 24 | } 25 | 26 | function void main() { 27 | let int i; 28 | start(); 29 | 30 | for(i = 0; i < 1000; i++) { 31 | run(); 32 | } 33 | 34 | print(int(end())); 35 | } -------------------------------------------------------------------------------- /test/asm/bench2.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | int run() { 7 | int N = 16384; 8 | int M = 200; 9 | int final = 0; 10 | int i, t; 11 | 12 | char *buf = (char*)malloc(N); 13 | for (t = 0; t < M; t++) { 14 | for (i = 0; i < N; i++) 15 | buf[i] = (i + final)%256; 16 | for (i = 0; i < N; i++) 17 | final += buf[i] & 1; 18 | final = final % 1000; 19 | } 20 | 21 | return final; 22 | } 23 | 24 | int main() { 25 | int f, i; 26 | 27 | for(i = 0; i < 1000; i++) { 28 | f = run(); 29 | } 30 | 31 | // Needed so that gcc doesn't remove the code as dead 32 | printf("%d", f); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/asm/bench2.js: -------------------------------------------------------------------------------- 1 | 2 | if(!Math.imul) { 3 | Math.imul = function(x, y) { return x * y; }; 4 | } 5 | 6 | var MB = 1024 * 1024; 7 | var SIZE = 256 * MB; 8 | var STACK_SIZE = 2 * MB; 9 | var HEAP_SIZE = SIZE - STACK_SIZE; 10 | var buffer = new ArrayBuffer(SIZE); 11 | 12 | var asm = (function (global, env, buffer) { 13 | "use asm"; 14 | 15 | var stackSize = env.STACK_SIZE|0; 16 | var heapSize = env.HEAP_SIZE|0; 17 | var totalSize = env.TOTAL_SIZE|0; 18 | var assertEqual = env.assertEqual; 19 | var print = env.print; 20 | var start = env.start; 21 | var end = env.end; 22 | 23 | var U1 = new global.Uint8Array(buffer); 24 | var I1 = new global.Int8Array(buffer); 25 | var U2 = new global.Uint16Array(buffer); 26 | var I2 = new global.Int16Array(buffer); 27 | var U4 = new global.Uint32Array(buffer); 28 | var I4 = new global.Int32Array(buffer); 29 | var F4 = new global.Float32Array(buffer); 30 | var F8 = new global.Float64Array(buffer); 31 | 32 | var acos = global.Math.acos; 33 | var asin = global.Math.asin; 34 | var atan = global.Math.atan; 35 | var cos = global.Math.cos; 36 | var sin = global.Math.sin; 37 | var tan = global.Math.tan; 38 | var ceil = global.Math.ceil; 39 | var floor = global.Math.floor; 40 | var exp = global.Math.exp; 41 | var log = global.Math.log; 42 | var sqrt = global.Math.sqrt; 43 | var abs = global.Math.abs; 44 | var atan2 = global.Math.atan2; 45 | var pow = global.Math.pow; 46 | var imul = global.Math.imul; 47 | 48 | function run() { 49 | var _ = 0, N = 0, M = 0, final = 0, buf = 0, t = 0, i = 0, $SP = 0; 50 | U4[1] = (U4[1] | 0) - 32768; 51 | $SP = U4[1] | 0; 52 | N = 16384; 53 | M = 200; 54 | final = 0; 55 | _; 56 | for (t = 0; (t | 0) < (M | 0); t = (t | 0) + 1 | 0) { 57 | for (i = 0; (i | 0) < (N | 0); i = (i | 0) + 1 | 0) { 58 | U1[((($SP) >> 0) + i) >> 0] = (((i | 0) + (final | 0) | 0 | 0) % 256 | 0) & 255; 59 | } 60 | for (i = 0; (i | 0) < (N | 0); i = (i | 0) + 1 | 0) { 61 | final = ((final | 0) + (U1[((($SP) >> 0) + i) >> 0] >>> 0) | 0) & 1; 62 | } 63 | final = (final | 0) % 1000 | 0; 64 | } 65 | U4[1] = (U4[1] | 0) + 32768; 66 | return 0.0; 67 | } 68 | function main() { 69 | var _ = 0, i = 0, $SP = 0; 70 | U4[1] = totalSize; 71 | U4[0] = 4; 72 | start(); 73 | for (i = 0; (i | 0) < 1000; _ = i, i = (i | 0) + 1 | 0, _) { 74 | run(); 75 | } 76 | print(end() | 0); 77 | } 78 | 79 | return { main: main }; 80 | 81 | })({ Uint8Array: Uint8Array, 82 | Int8Array: Int8Array, 83 | Uint16Array: Uint16Array, 84 | Int16Array: Int16Array, 85 | Uint32Array: Uint32Array, 86 | Int32Array: Int32Array, 87 | Float32Array: Float32Array, 88 | Float64Array: Float64Array, 89 | Math: Math }, 90 | { HEAP_SIZE: HEAP_SIZE, 91 | STACK_SIZE: STACK_SIZE, 92 | TOTAL_SIZE: SIZE, 93 | assertEqual: assertEqual, 94 | print: _print, 95 | start: start, 96 | end: end }, 97 | buffer); 98 | 99 | 100 | function assertEqual(val1, val2) { 101 | var err = true; 102 | var msg; 103 | if(val1 | 0 !== val1) { 104 | if(Math.abs(val1 - val2) < .00000001) { 105 | err = false; 106 | } 107 | else { 108 | msg = 'eps'; 109 | } 110 | } 111 | else if(val1 === val2) { 112 | err = false; 113 | } 114 | 115 | if(err) { 116 | throw new Error(val1 + ' does not equal ' + val2); 117 | } 118 | } 119 | 120 | function _print(/* arg1, arg2, ..., argN */) { 121 | var func = ((typeof console !== 'undefined' && console.log) || print); 122 | func.apply(null, arguments); 123 | } 124 | 125 | var _time; 126 | function start() { 127 | _time = Date.now(); 128 | } 129 | 130 | function end() { 131 | return Date.now() - _time; 132 | } 133 | 134 | asm.main(); 135 | -------------------------------------------------------------------------------- /test/asm/bench2.ljs: -------------------------------------------------------------------------------- 1 | 2 | extern start, end, print; 3 | 4 | function void run() { 5 | let int N = 16384; 6 | let int M = 200; 7 | let int final = 0; 8 | let u8 buf[16384]; 9 | let int t, i; 10 | 11 | for(t = 0; t < M; t = t + 1) { 12 | for(i = 0; i < N; i = i + 1) { 13 | buf[i] = (i + final) % 256; 14 | } 15 | 16 | for(i = 0; i < N; i = i + 1) { 17 | final = final + buf[i] & 1; 18 | } 19 | 20 | final = final % 1000; 21 | } 22 | } 23 | 24 | function void main() { 25 | let int i; 26 | start(); 27 | 28 | for(i = 0; i < 1000; i++) { 29 | run(); 30 | } 31 | 32 | print(int(end())); 33 | } -------------------------------------------------------------------------------- /test/asm/bridge.js: -------------------------------------------------------------------------------- 1 | 2 | let int bar[500]; 3 | 4 | function int* foo() { 5 | return bar + 10; 6 | } 7 | 8 | function a() { 9 | let x = foo(); 10 | } 11 | -------------------------------------------------------------------------------- /test/asm/functions.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | if(!Math.imul) { 4 | Math.imul = function(x, y) { return x * y; }; 5 | } 6 | 7 | var MB = 1024 * 1024; 8 | var SIZE = 256 * MB; 9 | var STACK_SIZE = 2 * MB; 10 | var HEAP_SIZE = SIZE - STACK_SIZE; 11 | var buffer = new ArrayBuffer(SIZE); 12 | 13 | if(typeof window !== 'undefined') { 14 | window.U1 = new Uint8Array(buffer); 15 | window.I1 = new Int8Array(buffer); 16 | window.U2 = new Uint16Array(buffer); 17 | window.I2 = new Int16Array(buffer); 18 | window.U4 = new Uint32Array(buffer); 19 | window.I4 = new Int32Array(buffer); 20 | window.F4 = new Float32Array(buffer); 21 | window.F8 = new Float64Array(buffer); 22 | 23 | window.asmBuffer = buffer; 24 | } 25 | 26 | var asm = (function (global, env, buffer) { 27 | "use asm"; 28 | 29 | var stackSize = env.STACK_SIZE|0; 30 | var heapSize = env.HEAP_SIZE|0; 31 | var totalSize = env.TOTAL_SIZE|0; 32 | 33 | var assertEqual = env.assertEqual; 34 | 35 | var U1 = new global.Uint8Array(buffer); 36 | var I1 = new global.Int8Array(buffer); 37 | var U2 = new global.Uint16Array(buffer); 38 | var I2 = new global.Int16Array(buffer); 39 | var U4 = new global.Uint32Array(buffer); 40 | var I4 = new global.Int32Array(buffer); 41 | var F4 = new global.Float32Array(buffer); 42 | var F8 = new global.Float64Array(buffer); 43 | 44 | var acos = global.Math.acos; 45 | var asin = global.Math.asin; 46 | var atan = global.Math.atan; 47 | var cos = global.Math.cos; 48 | var sin = global.Math.sin; 49 | var tan = global.Math.tan; 50 | var ceil = global.Math.ceil; 51 | var floor = global.Math.floor; 52 | var exp = global.Math.exp; 53 | var log = global.Math.log; 54 | var sqrt = global.Math.sqrt; 55 | var abs = global.Math.abs; 56 | var atan2 = global.Math.atan2; 57 | var pow = global.Math.pow; 58 | var imul = global.Math.imul; 59 | 60 | var globalSP = 64; 61 | function add1(x) { 62 | x = x | 0; 63 | var $SP = 0; 64 | return (x | 0) + 1 | 0 | 0; 65 | } 66 | function square(x, y) { 67 | x = +x; 68 | y = +y; 69 | var $SP = 0; 70 | return +(x * x + +(add1(~~(y * y)) | 0 | 0)); 71 | } 72 | function main() { 73 | var $SP = 0; 74 | U4[1] = totalSize - 64; 75 | U4[0] = 4; 76 | assertEqual(+square(2.3, 4.5), 26.29); 77 | } 78 | function memcpy(dest, src, num) { 79 | dest = dest|0; src = src|0; num = num|0; 80 | var ret = 0; 81 | ret = dest|0; 82 | if ((dest&3) == (src&3)) { 83 | while (dest & 3) { 84 | if ((num|0) == 0) return ret|0; 85 | U1[(dest)]=U1[(src)]; 86 | dest = (dest+1)|0; 87 | src = (src+1)|0; 88 | num = (num-1)|0; 89 | } 90 | while ((num|0) >= 4) { 91 | U4[((dest)>>2)]=U4[((src)>>2)]; 92 | dest = (dest+4)|0; 93 | src = (src+4)|0; 94 | num = (num-4)|0; 95 | } 96 | } 97 | while ((num|0) > 0) { 98 | U1[(dest)]=U1[(src)]; 99 | dest = (dest+1)|0; 100 | src = (src+1)|0; 101 | num = (num-1)|0; 102 | } 103 | return ret|0; 104 | } 105 | 106 | function memset(ptr, value, num) { 107 | ptr = ptr|0; value = value|0; num = num|0; 108 | var stop = 0, value4 = 0, stop4 = 0, unaligned = 0; 109 | stop = (ptr + num)|0; 110 | if ((num|0) >= 20) { 111 | // This is unaligned, but quite large, so work hard to get to aligned settings 112 | value = value & 0xff; 113 | unaligned = ptr & 3; 114 | value4 = value | (value << 8) | (value << 16) | (value << 24); 115 | stop4 = stop & ~3; 116 | if (unaligned) { 117 | unaligned = (ptr + 4 - unaligned)|0; 118 | while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num 119 | U1[(ptr)]=value; 120 | ptr = (ptr+1)|0; 121 | } 122 | } 123 | while ((ptr|0) < (stop4|0)) { 124 | U4[((ptr)>>2)]=value4; 125 | ptr = (ptr+4)|0; 126 | } 127 | } 128 | while ((ptr|0) < (stop|0)) { 129 | U1[(ptr)]=value; 130 | ptr = (ptr+1)|0; 131 | } 132 | } 133 | 134 | return { main: main }; 135 | 136 | })({ Uint8Array: Uint8Array, 137 | Int8Array: Int8Array, 138 | Uint16Array: Uint16Array, 139 | Int16Array: Int16Array, 140 | Uint32Array: Uint32Array, 141 | Int32Array: Int32Array, 142 | Float32Array: Float32Array, 143 | Float64Array: Float64Array, 144 | Math: Math }, 145 | { assertEqual: assertEqual, 146 | HEAP_SIZE: HEAP_SIZE, 147 | STACK_SIZE: STACK_SIZE, 148 | TOTAL_SIZE: SIZE }, 149 | buffer); 150 | 151 | function assertEqual(val1, val2) { 152 | var err = true; 153 | var msg; 154 | if(val1 | 0 !== val1) { 155 | if(Math.abs(val1 - val2) < .00000001) { 156 | err = false; 157 | } 158 | else { 159 | msg = 'eps'; 160 | } 161 | } 162 | else if(val1 === val2) { 163 | err = false; 164 | } 165 | 166 | if(err) { 167 | throw new Error(val1 + ' does not equal ' + val2); 168 | } 169 | } 170 | 171 | function _print(/* arg1, arg2, ..., argN */) { 172 | var func = ((typeof console !== 'undefined' && console.log) || print); 173 | func.apply(null, arguments); 174 | } 175 | 176 | var _time; 177 | function start() { 178 | _time = Date.now(); 179 | } 180 | 181 | function end() { 182 | return Date.now() - _time; 183 | } 184 | 185 | asm.main(); 186 | })(); 187 | 188 | -------------------------------------------------------------------------------- /test/asm/functions.ljs: -------------------------------------------------------------------------------- 1 | 2 | extern assertEqual; 3 | 4 | function int add1(int x) { 5 | return x + 1; 6 | } 7 | 8 | function double square(double x, double y) { 9 | // add1 takes an integer, so it rounds the result 10 | return x*x + add1(y*y); 11 | } 12 | 13 | function void main() { 14 | assertEqual(square(2.3, 4.5), 26.29); 15 | } 16 | -------------------------------------------------------------------------------- /test/asm/memory.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | if(!Math.imul) { 4 | Math.imul = function(x, y) { return x * y; }; 5 | } 6 | 7 | var MB = 1024 * 1024; 8 | var SIZE = 256 * MB; 9 | var STACK_SIZE = 2 * MB; 10 | var HEAP_SIZE = SIZE - STACK_SIZE; 11 | var buffer = new ArrayBuffer(SIZE); 12 | 13 | if(typeof window !== 'undefined') { 14 | window.U1 = new Uint8Array(buffer); 15 | window.I1 = new Int8Array(buffer); 16 | window.U2 = new Uint16Array(buffer); 17 | window.I2 = new Int16Array(buffer); 18 | window.U4 = new Uint32Array(buffer); 19 | window.I4 = new Int32Array(buffer); 20 | window.F4 = new Float32Array(buffer); 21 | window.F8 = new Float64Array(buffer); 22 | 23 | window.asmBuffer = buffer; 24 | } 25 | 26 | var asm = (function (global, env, buffer) { 27 | "use asm"; 28 | 29 | var stackSize = env.STACK_SIZE|0; 30 | var heapSize = env.HEAP_SIZE|0; 31 | var totalSize = env.TOTAL_SIZE|0; 32 | 33 | var assertEqual = env.assertEqual; 34 | 35 | var U1 = new global.Uint8Array(buffer); 36 | var I1 = new global.Int8Array(buffer); 37 | var U2 = new global.Uint16Array(buffer); 38 | var I2 = new global.Int16Array(buffer); 39 | var U4 = new global.Uint32Array(buffer); 40 | var I4 = new global.Int32Array(buffer); 41 | var F4 = new global.Float32Array(buffer); 42 | var F8 = new global.Float64Array(buffer); 43 | 44 | var acos = global.Math.acos; 45 | var asin = global.Math.asin; 46 | var atan = global.Math.atan; 47 | var cos = global.Math.cos; 48 | var sin = global.Math.sin; 49 | var tan = global.Math.tan; 50 | var ceil = global.Math.ceil; 51 | var floor = global.Math.floor; 52 | var exp = global.Math.exp; 53 | var log = global.Math.log; 54 | var sqrt = global.Math.sqrt; 55 | var abs = global.Math.abs; 56 | var atan2 = global.Math.atan2; 57 | var pow = global.Math.pow; 58 | var imul = global.Math.imul; 59 | 60 | var globalSP = 144; 61 | function testLocalArray() { 62 | var arr = 0, $SP = 0; 63 | U4[1] = (U4[1] | 0) - 80 | 0; 64 | $SP = U4[1] | 0; 65 | I4[(($SP) + (0 * 4 | 0)) >> 2] = 1; 66 | I4[(($SP) + (15 * 4 | 0)) >> 2] = 2; 67 | assertEqual(I4[(($SP) + (0 * 4 | 0)) >> 2] | 0, 1); 68 | assertEqual(I4[(($SP) + (15 * 4 | 0)) >> 2] | 0, 2); 69 | I4[(((totalSize - globalSP | 0) + 64 | 0) + (10 * 4 | 0)) >> 2] = (I4[(((totalSize - globalSP | 0) + 64 | 0) + (10 * 4 | 0)) >> 2] | 0) + 1 | 0; 70 | U4[1] = (U4[1] | 0) + 80; 71 | } 72 | function main() { 73 | var x = 0, y = 0, z = 0, $SP = 0; 74 | U4[1] = totalSize - 144; 75 | U4[0] = 4; 76 | U4[1] = (U4[1] | 0) - 24 | 0; 77 | $SP = U4[1] | 0; 78 | I4[(((totalSize - globalSP | 0) + 64 | 0) + (10 * 4 | 0)) >> 2] = 0; 79 | I4[($SP) >> 2] = 42; 80 | U4[(($SP) + 8 | 0) >> 2] = ($SP) | 0 | 0 | 0; 81 | U4[(($SP) + 16 | 0) >> 2] = ($SP) + 8 | 0 | 0 | 0; 82 | I4[(U4[(($SP) + 8 | 0) >> 2]) >> 2] = 1; 83 | assertEqual(I4[($SP) >> 2] | 0, 1); 84 | I4[(U4[(U4[(($SP) + 16 | 0) >> 2]) >> 2]) >> 2] = 12; 85 | assertEqual(I4[($SP) >> 2] | 0, 12); 86 | assertEqual(I4[(U4[(U4[(($SP) + 16 | 0) >> 2]) >> 2]) >> 2] | 0, 12); 87 | testLocalArray(); 88 | testLocalArray(); 89 | testLocalArray(); 90 | assertEqual(I4[(((totalSize - globalSP | 0) + 64 | 0) + (10 * 4 | 0)) >> 2] | 0, 3); 91 | U4[1] = (U4[1] | 0) + 24; 92 | } 93 | function memcpy(dest, src, num) { 94 | dest = dest|0; src = src|0; num = num|0; 95 | var ret = 0; 96 | ret = dest|0; 97 | if ((dest&3) == (src&3)) { 98 | while (dest & 3) { 99 | if ((num|0) == 0) return ret|0; 100 | U1[(dest)]=U1[(src)]; 101 | dest = (dest+1)|0; 102 | src = (src+1)|0; 103 | num = (num-1)|0; 104 | } 105 | while ((num|0) >= 4) { 106 | U4[((dest)>>2)]=U4[((src)>>2)]; 107 | dest = (dest+4)|0; 108 | src = (src+4)|0; 109 | num = (num-4)|0; 110 | } 111 | } 112 | while ((num|0) > 0) { 113 | U1[(dest)]=U1[(src)]; 114 | dest = (dest+1)|0; 115 | src = (src+1)|0; 116 | num = (num-1)|0; 117 | } 118 | return ret|0; 119 | } 120 | 121 | function memset(ptr, value, num) { 122 | ptr = ptr|0; value = value|0; num = num|0; 123 | var stop = 0, value4 = 0, stop4 = 0, unaligned = 0; 124 | stop = (ptr + num)|0; 125 | if ((num|0) >= 20) { 126 | // This is unaligned, but quite large, so work hard to get to aligned settings 127 | value = value & 0xff; 128 | unaligned = ptr & 3; 129 | value4 = value | (value << 8) | (value << 16) | (value << 24); 130 | stop4 = stop & ~3; 131 | if (unaligned) { 132 | unaligned = (ptr + 4 - unaligned)|0; 133 | while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num 134 | U1[(ptr)]=value; 135 | ptr = (ptr+1)|0; 136 | } 137 | } 138 | while ((ptr|0) < (stop4|0)) { 139 | U4[((ptr)>>2)]=value4; 140 | ptr = (ptr+4)|0; 141 | } 142 | } 143 | while ((ptr|0) < (stop|0)) { 144 | U1[(ptr)]=value; 145 | ptr = (ptr+1)|0; 146 | } 147 | } 148 | 149 | return { main: main }; 150 | 151 | })({ Uint8Array: Uint8Array, 152 | Int8Array: Int8Array, 153 | Uint16Array: Uint16Array, 154 | Int16Array: Int16Array, 155 | Uint32Array: Uint32Array, 156 | Int32Array: Int32Array, 157 | Float32Array: Float32Array, 158 | Float64Array: Float64Array, 159 | Math: Math }, 160 | { assertEqual: assertEqual, 161 | HEAP_SIZE: HEAP_SIZE, 162 | STACK_SIZE: STACK_SIZE, 163 | TOTAL_SIZE: SIZE }, 164 | buffer); 165 | 166 | function assertEqual(val1, val2) { 167 | var err = true; 168 | var msg; 169 | if(val1 | 0 !== val1) { 170 | if(Math.abs(val1 - val2) < .00000001) { 171 | err = false; 172 | } 173 | else { 174 | msg = 'eps'; 175 | } 176 | } 177 | else if(val1 === val2) { 178 | err = false; 179 | } 180 | 181 | if(err) { 182 | throw new Error(val1 + ' does not equal ' + val2); 183 | } 184 | } 185 | 186 | function _print(/* arg1, arg2, ..., argN */) { 187 | var func = ((typeof console !== 'undefined' && console.log) || print); 188 | func.apply(null, arguments); 189 | } 190 | 191 | var _time; 192 | function start() { 193 | _time = Date.now(); 194 | } 195 | 196 | function end() { 197 | return Date.now() - _time; 198 | } 199 | 200 | asm.main(); 201 | })(); 202 | 203 | -------------------------------------------------------------------------------- /test/asm/memory.ljs: -------------------------------------------------------------------------------- 1 | 2 | extern assertEqual; 3 | 4 | let int NUMS[20]; 5 | 6 | function void testLocalArray() { 7 | // Test local arrays 8 | let int arr[20]; 9 | arr[0] = 1; 10 | arr[15] = 2; 11 | 12 | assertEqual(arr[0], 1); 13 | assertEqual(arr[15], 2); 14 | 15 | NUMS[10] = NUMS[10] + 1; 16 | } 17 | 18 | function void main() { 19 | NUMS[10] = 0; 20 | 21 | // Test local primitives & pointers 22 | let int x = 42; 23 | let int *y = &x; 24 | let int **z = &y; 25 | 26 | *y = 1; 27 | assertEqual(x, 1); 28 | 29 | **z = 12; 30 | assertEqual(x, 12); 31 | assertEqual(***(&z), 12); 32 | 33 | // Call a function that allocates an array on the stack and also 34 | // manipulates data in the global stack 35 | testLocalArray(); 36 | testLocalArray(); 37 | testLocalArray(); 38 | 39 | // Test global stack memory 40 | assertEqual(NUMS[10], 3); 41 | } 42 | -------------------------------------------------------------------------------- /test/asm/primitives.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | if(!Math.imul) { 4 | Math.imul = function(x, y) { return x * y; }; 5 | } 6 | 7 | var MB = 1024 * 1024; 8 | var SIZE = 256 * MB; 9 | var STACK_SIZE = 2 * MB; 10 | var HEAP_SIZE = SIZE - STACK_SIZE; 11 | var buffer = new ArrayBuffer(SIZE); 12 | 13 | if(typeof window !== 'undefined') { 14 | window.U1 = new Uint8Array(buffer); 15 | window.I1 = new Int8Array(buffer); 16 | window.U2 = new Uint16Array(buffer); 17 | window.I2 = new Int16Array(buffer); 18 | window.U4 = new Uint32Array(buffer); 19 | window.I4 = new Int32Array(buffer); 20 | window.F4 = new Float32Array(buffer); 21 | window.F8 = new Float64Array(buffer); 22 | 23 | window.asmBuffer = buffer; 24 | } 25 | 26 | var asm = (function (global, env, buffer) { 27 | "use asm"; 28 | 29 | var stackSize = env.STACK_SIZE|0; 30 | var heapSize = env.HEAP_SIZE|0; 31 | var totalSize = env.TOTAL_SIZE|0; 32 | 33 | var assertEqual = env.assertEqual; 34 | 35 | var U1 = new global.Uint8Array(buffer); 36 | var I1 = new global.Int8Array(buffer); 37 | var U2 = new global.Uint16Array(buffer); 38 | var I2 = new global.Int16Array(buffer); 39 | var U4 = new global.Uint32Array(buffer); 40 | var I4 = new global.Int32Array(buffer); 41 | var F4 = new global.Float32Array(buffer); 42 | var F8 = new global.Float64Array(buffer); 43 | 44 | var acos = global.Math.acos; 45 | var asin = global.Math.asin; 46 | var atan = global.Math.atan; 47 | var cos = global.Math.cos; 48 | var sin = global.Math.sin; 49 | var tan = global.Math.tan; 50 | var ceil = global.Math.ceil; 51 | var floor = global.Math.floor; 52 | var exp = global.Math.exp; 53 | var log = global.Math.log; 54 | var sqrt = global.Math.sqrt; 55 | var abs = global.Math.abs; 56 | var atan2 = global.Math.atan2; 57 | var pow = global.Math.pow; 58 | var imul = global.Math.imul; 59 | 60 | var globalSP = 64; 61 | function main() { 62 | var _ = 0, _$1 = 0, _$2 = 0, _$3 = 0, _$4 = 0, x = 0, y = 0, z = 0.0, w = 0.0, i = 0, $SP = 0; 63 | U4[1] = totalSize - 64; 64 | U4[0] = 4; 65 | assertEqual(1, 1); 66 | assertEqual(1, 1); 67 | assertEqual(2, 2); 68 | assertEqual(2, 2); 69 | assertEqual(4, 4); 70 | assertEqual(4, 4); 71 | assertEqual(4, 4); 72 | assertEqual(8, 8); 73 | assertEqual(-1, -1); 74 | assertEqual(-1, -1); 75 | assertEqual(-1, -1); 76 | x = 8; 77 | y = 6; 78 | assertEqual((x | 0) + (y | 0) | 0, 14); 79 | assertEqual((x | 0) - (y | 0) | 0, 2); 80 | assertEqual((x | 0) / (y | 0) | 0, 1); 81 | assertEqual(imul(x, y) | 0, 48); 82 | assertEqual((x | 0) % (y | 0) | 0, 2); 83 | z = 5.1; 84 | w = +6.0; 85 | assertEqual(z + w, 11.1); 86 | assertEqual(z - w, -0.9); 87 | assertEqual(z / w, 0.85); 88 | assertEqual(z * w, 30.6); 89 | assertEqual(z * +(x | 0), 40.8); 90 | x = 5; 91 | if ((x | 0) > 3) { 92 | x = 10; 93 | } 94 | assertEqual(x | 0, 10); 95 | x = 5; 96 | { 97 | _ = 0; 98 | { 99 | _$1 = 0; 100 | if ((x | 0 | 0 | 0) > 3) { 101 | if ((x | 0 | 0 | 0) < 10) { 102 | _$1 = 1; 103 | } 104 | } 105 | { 106 | if (_$1) { 107 | if (1) { 108 | _ = 1; 109 | } 110 | } 111 | } 112 | } 113 | { 114 | if (_) { 115 | x = 15; 116 | } 117 | } 118 | } 119 | x = 5; 120 | y = 6; 121 | { 122 | _$2 = 0; 123 | { 124 | { 125 | _$3 = 0; 126 | { 127 | if ((x | 0 | 0 | 0) > 1) { 128 | _$3 = 1; 129 | } 130 | if ((y | 0 | 0 | 0) > 10) { 131 | _$3 = 1; 132 | } 133 | } 134 | { 135 | if (_$3) { 136 | _$2 = 1; 137 | } 138 | } 139 | } 140 | if (0) { 141 | _$2 = 1; 142 | } 143 | } 144 | { 145 | if (_$2) { 146 | x = 15; 147 | } 148 | } 149 | } 150 | assertEqual(x | 0, 15); 151 | x = 0; 152 | y = 1; 153 | while ((x | 0) < 10) { 154 | x = (x | 0) + 1 | 0; 155 | y = imul(y, 2) | 0; 156 | } 157 | assertEqual(y | 0, 1024); 158 | y = 1; 159 | for (i = 0; (i | 0) < 10; _$4 = i, i = (i | 0) + 1 | 0, _$4) { 160 | y = imul(y, 2) | 0; 161 | } 162 | assertEqual(y | 0, 1024); 163 | } 164 | function memcpy(dest, src, num) { 165 | dest = dest|0; src = src|0; num = num|0; 166 | var ret = 0; 167 | ret = dest|0; 168 | if ((dest&3) == (src&3)) { 169 | while (dest & 3) { 170 | if ((num|0) == 0) return ret|0; 171 | U1[(dest)]=U1[(src)]; 172 | dest = (dest+1)|0; 173 | src = (src+1)|0; 174 | num = (num-1)|0; 175 | } 176 | while ((num|0) >= 4) { 177 | U4[((dest)>>2)]=U4[((src)>>2)]; 178 | dest = (dest+4)|0; 179 | src = (src+4)|0; 180 | num = (num-4)|0; 181 | } 182 | } 183 | while ((num|0) > 0) { 184 | U1[(dest)]=U1[(src)]; 185 | dest = (dest+1)|0; 186 | src = (src+1)|0; 187 | num = (num-1)|0; 188 | } 189 | return ret|0; 190 | } 191 | 192 | function memset(ptr, value, num) { 193 | ptr = ptr|0; value = value|0; num = num|0; 194 | var stop = 0, value4 = 0, stop4 = 0, unaligned = 0; 195 | stop = (ptr + num)|0; 196 | if ((num|0) >= 20) { 197 | // This is unaligned, but quite large, so work hard to get to aligned settings 198 | value = value & 0xff; 199 | unaligned = ptr & 3; 200 | value4 = value | (value << 8) | (value << 16) | (value << 24); 201 | stop4 = stop & ~3; 202 | if (unaligned) { 203 | unaligned = (ptr + 4 - unaligned)|0; 204 | while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num 205 | U1[(ptr)]=value; 206 | ptr = (ptr+1)|0; 207 | } 208 | } 209 | while ((ptr|0) < (stop4|0)) { 210 | U4[((ptr)>>2)]=value4; 211 | ptr = (ptr+4)|0; 212 | } 213 | } 214 | while ((ptr|0) < (stop|0)) { 215 | U1[(ptr)]=value; 216 | ptr = (ptr+1)|0; 217 | } 218 | } 219 | 220 | return { main: main }; 221 | 222 | })({ Uint8Array: Uint8Array, 223 | Int8Array: Int8Array, 224 | Uint16Array: Uint16Array, 225 | Int16Array: Int16Array, 226 | Uint32Array: Uint32Array, 227 | Int32Array: Int32Array, 228 | Float32Array: Float32Array, 229 | Float64Array: Float64Array, 230 | Math: Math }, 231 | { assertEqual: assertEqual, 232 | HEAP_SIZE: HEAP_SIZE, 233 | STACK_SIZE: STACK_SIZE, 234 | TOTAL_SIZE: SIZE }, 235 | buffer); 236 | 237 | function assertEqual(val1, val2) { 238 | var err = true; 239 | var msg; 240 | if(val1 | 0 !== val1) { 241 | if(Math.abs(val1 - val2) < .00000001) { 242 | err = false; 243 | } 244 | else { 245 | msg = 'eps'; 246 | } 247 | } 248 | else if(val1 === val2) { 249 | err = false; 250 | } 251 | 252 | if(err) { 253 | throw new Error(val1 + ' does not equal ' + val2); 254 | } 255 | } 256 | 257 | function _print(/* arg1, arg2, ..., argN */) { 258 | var func = ((typeof console !== 'undefined' && console.log) || print); 259 | func.apply(null, arguments); 260 | } 261 | 262 | var _time; 263 | function start() { 264 | _time = Date.now(); 265 | } 266 | 267 | function end() { 268 | return Date.now() - _time; 269 | } 270 | 271 | asm.main(); 272 | })(); 273 | 274 | -------------------------------------------------------------------------------- /test/asm/primitives.ljs: -------------------------------------------------------------------------------- 1 | 2 | extern assertEqual; 3 | 4 | function void main() { 5 | assertEqual(sizeof(u8), 1); 6 | assertEqual(sizeof(i8), 1); 7 | assertEqual(sizeof(u16), 2); 8 | assertEqual(sizeof(i16), 2); 9 | assertEqual(sizeof(u32), 4); 10 | assertEqual(sizeof(i32), 4); 11 | assertEqual(sizeof(float), 4); 12 | assertEqual(sizeof(double), 8); 13 | 14 | assertEqual(i8(-1), -1); 15 | assertEqual(i16(-1), -1); 16 | assertEqual(i32(-1), -1); 17 | /* assertEqual(u8(-1), 255); */ 18 | /* assertEqual(u16(-1), 65535); */ 19 | /* assertEqual(u32(-1), 4294967295); */ 20 | 21 | // integer arithmetic 22 | let int x = 8; 23 | let int y = 6; 24 | assertEqual(x + y, 14); 25 | assertEqual(x - y, 2); 26 | assertEqual(x / y, 1); 27 | assertEqual(x * y, 48); 28 | assertEqual(x % y, 2); 29 | 30 | // double arithmetic 31 | let double z = 5.1; 32 | let double w = 6.0; 33 | assertEqual(z + w, 11.1); 34 | assertEqual(z - w, -.9); 35 | assertEqual(z / w, .85); 36 | assertEqual(z * w, 30.6); 37 | 38 | // mixing ints and doubles coerces everything to doubles 39 | assertEqual(z * x, 40.8); 40 | 41 | // if 42 | x = 5; 43 | if(x > 3) { 44 | x = 10; 45 | } 46 | assertEqual(x, 10); 47 | 48 | // conditionals 49 | x = 5; 50 | if(x > 3 && x < 10 && 1) { 51 | x = 15; 52 | } 53 | 54 | x = 5; 55 | y = 6; 56 | if(x > 1 || y > 10 || 0) { 57 | x = 15; 58 | } 59 | assertEqual(x, 15); 60 | 61 | // while loop 62 | x = 0; 63 | y = 1; 64 | while(x < 10) { 65 | x = x + 1; 66 | y = y * 2; 67 | } 68 | assertEqual(y, 1024); 69 | 70 | // for loop 71 | y = 1; 72 | let int i; // only works when declaring outside loop (for now) 73 | for(i=0; i<10; i++) { 74 | y = y * 2; 75 | } 76 | assertEqual(y, 1024); 77 | } 78 | -------------------------------------------------------------------------------- /test/asm/types.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | if(!Math.imul) { 4 | Math.imul = function(x, y) { return x * y; }; 5 | } 6 | 7 | var MB = 1024 * 1024; 8 | var SIZE = 256 * MB; 9 | var STACK_SIZE = 2 * MB; 10 | var HEAP_SIZE = SIZE - STACK_SIZE; 11 | var buffer = new ArrayBuffer(SIZE); 12 | 13 | if(typeof window !== 'undefined') { 14 | window.U1 = new Uint8Array(buffer); 15 | window.I1 = new Int8Array(buffer); 16 | window.U2 = new Uint16Array(buffer); 17 | window.I2 = new Int16Array(buffer); 18 | window.U4 = new Uint32Array(buffer); 19 | window.I4 = new Int32Array(buffer); 20 | window.F4 = new Float32Array(buffer); 21 | window.F8 = new Float64Array(buffer); 22 | 23 | window.asmBuffer = buffer; 24 | } 25 | 26 | var asm = (function (global, env, buffer) { 27 | "use asm"; 28 | 29 | var stackSize = env.STACK_SIZE|0; 30 | var heapSize = env.HEAP_SIZE|0; 31 | var totalSize = env.TOTAL_SIZE|0; 32 | 33 | var assertEqual = env.assertEqual; 34 | 35 | var U1 = new global.Uint8Array(buffer); 36 | var I1 = new global.Int8Array(buffer); 37 | var U2 = new global.Uint16Array(buffer); 38 | var I2 = new global.Int16Array(buffer); 39 | var U4 = new global.Uint32Array(buffer); 40 | var I4 = new global.Int32Array(buffer); 41 | var F4 = new global.Float32Array(buffer); 42 | var F8 = new global.Float64Array(buffer); 43 | 44 | var acos = global.Math.acos; 45 | var asin = global.Math.asin; 46 | var atan = global.Math.atan; 47 | var cos = global.Math.cos; 48 | var sin = global.Math.sin; 49 | var tan = global.Math.tan; 50 | var ceil = global.Math.ceil; 51 | var floor = global.Math.floor; 52 | var exp = global.Math.exp; 53 | var log = global.Math.log; 54 | var sqrt = global.Math.sqrt; 55 | var abs = global.Math.abs; 56 | var atan2 = global.Math.atan2; 57 | var pow = global.Math.pow; 58 | var imul = global.Math.imul; 59 | 60 | var globalSP = 64; 61 | function Point$Point(thisPtr, x, y) { 62 | thisPtr = thisPtr | 0; 63 | x = +x; 64 | y = +y; 65 | var $SP = 0; 66 | F8[(thisPtr) >> 3] = x; 67 | F8[((thisPtr) + 8 | 0) >> 3] = y; 68 | } 69 | function bar(p) { 70 | p = p | 0; 71 | var _ = 0.0, c = 0, $SP = 0; 72 | U4[1] = (U4[1] | 0) - 16 | 0; 73 | $SP = U4[1] | 0; 74 | F8[(($SP)) >> 3] = 3.4; 75 | I4[((($SP)) + 8 | 0) >> 2] = 5; 76 | U4[((($SP)) + 12 | 0) >> 2] = p | 0; 77 | return +(_ = +(+(I4[((($SP)) + 8 | 0) >> 2] | 0 | 0) + +F8[(U4[((($SP)) + 12 | 0) >> 2] | 0) >> 3]), U4[1] = (U4[1] | 0) + 16 | 0, _); 78 | U4[1] = (U4[1] | 0) + 16; 79 | return 0.0; 80 | } 81 | function foo() { 82 | var _ = 0.0, p1 = 0, p2 = 0, p3 = 0, $SP = 0; 83 | U4[1] = (U4[1] | 0) - 48 | 0; 84 | $SP = U4[1] | 0; 85 | (Point$Point(($SP) | 0 | 0 | 0, 5.5, 6.6), F8[($SP) >> 3]); 86 | (Point$Point(($SP) + 16 | 0 | 0 | 0, 7.7, 8.8), F8[(($SP) + 16 | 0) >> 3]); 87 | (Point$Point(($SP) + 32 | 0 | 0 | 0, 9.9, 1.1), F8[(($SP) + 32 | 0) >> 3]); 88 | return +(_ = +(+F8[(($SP) + 16 | 0) >> 3] + +F8[((($SP) + 32 | 0) + 8 | 0) >> 3]), U4[1] = (U4[1] | 0) + 48 | 0, _); 89 | U4[1] = (U4[1] | 0) + 48; 90 | return 0.0; 91 | } 92 | function main() { 93 | var p1 = 0, p2 = 0, p3 = 0, p4 = 0, p5 = 0, p = 0, v = 0, $SP = 0; 94 | U4[1] = totalSize - 64; 95 | U4[0] = 4; 96 | U4[1] = (U4[1] | 0) - 88 | 0; 97 | $SP = U4[1] | 0; 98 | (Point$Point(($SP) | 0 | 0 | 0, 1.2, 3.4), F8[($SP) >> 3]); 99 | (Point$Point(($SP) + 16 | 0 | 0 | 0, 1.3, 3.5), F8[(($SP) + 16 | 0) >> 3]); 100 | (Point$Point(($SP) + 32 | 0 | 0 | 0, 1.4, 3.6), F8[(($SP) + 32 | 0) >> 3]); 101 | (Point$Point(($SP) + 48 | 0 | 0 | 0, 1.5, 3.7), F8[(($SP) + 48 | 0) >> 3]); 102 | (Point$Point(($SP) + 64 | 0 | 0 | 0, 1.6, 3.8), F8[(($SP) + 64 | 0) >> 3]); 103 | assertEqual(+F8[(($SP) + 64 | 0) >> 3], 1.6); 104 | assertEqual(+F8[((($SP) + 32 | 0) + 8 | 0) >> 3], 3.6); 105 | p = ($SP) + 16 | 0 | 0 | 0; 106 | assertEqual(+F8[(p) >> 3], 1.3); 107 | assertEqual(+foo(), 8.8); 108 | assertEqual(+bar(($SP) | 0 | 0), 6.2); 109 | assertEqual(+F8[(($SP) + 64 | 0) >> 3], 1.6); 110 | assertEqual(+F8[((($SP) + 32 | 0) + 8 | 0) >> 3], 3.6); 111 | I4[(($SP) + 80 | 0) >> 2] = 512; 112 | assertEqual(U1[(((($SP) + 80 | 0) | 0) + 0) >> 0] | 0, 0); 113 | assertEqual(U1[(((($SP) + 80 | 0) | 0) + 1) >> 0] | 0, 2); 114 | assertEqual(U1[(((($SP) + 80 | 0) | 0) + 2) >> 0] | 0, 0); 115 | assertEqual(U1[(((($SP) + 80 | 0) | 0) + 3) >> 0] | 0, 0); 116 | U4[1] = (U4[1] | 0) + 88; 117 | return 0.0; 118 | } 119 | function memcpy(dest, src, num) { 120 | dest = dest|0; src = src|0; num = num|0; 121 | var ret = 0; 122 | ret = dest|0; 123 | if ((dest&3) == (src&3)) { 124 | while (dest & 3) { 125 | if ((num|0) == 0) return ret|0; 126 | U1[(dest)]=U1[(src)]; 127 | dest = (dest+1)|0; 128 | src = (src+1)|0; 129 | num = (num-1)|0; 130 | } 131 | while ((num|0) >= 4) { 132 | U4[((dest)>>2)]=U4[((src)>>2)]; 133 | dest = (dest+4)|0; 134 | src = (src+4)|0; 135 | num = (num-4)|0; 136 | } 137 | } 138 | while ((num|0) > 0) { 139 | U1[(dest)]=U1[(src)]; 140 | dest = (dest+1)|0; 141 | src = (src+1)|0; 142 | num = (num-1)|0; 143 | } 144 | return ret|0; 145 | } 146 | 147 | function memset(ptr, value, num) { 148 | ptr = ptr|0; value = value|0; num = num|0; 149 | var stop = 0, value4 = 0, stop4 = 0, unaligned = 0; 150 | stop = (ptr + num)|0; 151 | if ((num|0) >= 20) { 152 | // This is unaligned, but quite large, so work hard to get to aligned settings 153 | value = value & 0xff; 154 | unaligned = ptr & 3; 155 | value4 = value | (value << 8) | (value << 16) | (value << 24); 156 | stop4 = stop & ~3; 157 | if (unaligned) { 158 | unaligned = (ptr + 4 - unaligned)|0; 159 | while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num 160 | U1[(ptr)]=value; 161 | ptr = (ptr+1)|0; 162 | } 163 | } 164 | while ((ptr|0) < (stop4|0)) { 165 | U4[((ptr)>>2)]=value4; 166 | ptr = (ptr+4)|0; 167 | } 168 | } 169 | while ((ptr|0) < (stop|0)) { 170 | U1[(ptr)]=value; 171 | ptr = (ptr+1)|0; 172 | } 173 | } 174 | 175 | return { main: main }; 176 | 177 | })({ Uint8Array: Uint8Array, 178 | Int8Array: Int8Array, 179 | Uint16Array: Uint16Array, 180 | Int16Array: Int16Array, 181 | Uint32Array: Uint32Array, 182 | Int32Array: Int32Array, 183 | Float32Array: Float32Array, 184 | Float64Array: Float64Array, 185 | Math: Math }, 186 | { assertEqual: assertEqual, 187 | HEAP_SIZE: HEAP_SIZE, 188 | STACK_SIZE: STACK_SIZE, 189 | TOTAL_SIZE: SIZE }, 190 | buffer); 191 | 192 | function assertEqual(val1, val2) { 193 | var err = true; 194 | var msg; 195 | if(val1 | 0 !== val1) { 196 | if(Math.abs(val1 - val2) < .00000001) { 197 | err = false; 198 | } 199 | else { 200 | msg = 'eps'; 201 | } 202 | } 203 | else if(val1 === val2) { 204 | err = false; 205 | } 206 | 207 | if(err) { 208 | throw new Error(val1 + ' does not equal ' + val2); 209 | } 210 | } 211 | 212 | function _print(/* arg1, arg2, ..., argN */) { 213 | var func = ((typeof console !== 'undefined' && console.log) || print); 214 | func.apply(null, arguments); 215 | } 216 | 217 | var _time; 218 | function start() { 219 | _time = Date.now(); 220 | } 221 | 222 | function end() { 223 | return Date.now() - _time; 224 | } 225 | 226 | asm.main(); 227 | })(); 228 | 229 | -------------------------------------------------------------------------------- /test/asm/types.ljs: -------------------------------------------------------------------------------- 1 | 2 | extern assertEqual; 3 | 4 | struct Point { 5 | function void Point(double x, double y) { 6 | this->x = x; 7 | this->y = y; 8 | } 9 | 10 | double x, y; 11 | } 12 | 13 | struct Complex { 14 | double x; 15 | int y; 16 | Point *point; 17 | } 18 | 19 | union Value { 20 | u8 byte[4]; 21 | int x; 22 | } 23 | 24 | function double bar(Point *p) { 25 | let Complex c; 26 | c.x = 3.4; 27 | c.y = 5; 28 | c.point = p; 29 | 30 | return c.y + c.point->x; 31 | } 32 | 33 | function double foo() { 34 | let Point p1(5.5, 6.6); 35 | let Point p2(7.7, 8.8); 36 | let Point p3(9.9, 1.1); 37 | 38 | return p2.x + p3.y; 39 | } 40 | 41 | function double main() { 42 | let Point p1(1.2, 3.4); 43 | let Point p2(1.3, 3.5); 44 | let Point p3(1.4, 3.6); 45 | let Point p4(1.5, 3.7); 46 | let Point p5(1.6, 3.8); 47 | 48 | assertEqual(p5.x, 1.6); 49 | assertEqual(p3.y, 3.6); 50 | 51 | let Point *p = &p2; 52 | assertEqual(p->x, 1.3); 53 | 54 | assertEqual(foo(), 8.8); 55 | assertEqual(bar(&p1), 6.2); 56 | 57 | assertEqual(p5.x, 1.6); 58 | assertEqual(p3.y, 3.6); 59 | 60 | // Not working yet 61 | // let int x[5] = [5, 6, 7, 8, 9]; 62 | // assertEqual(x[0], 5); 63 | 64 | let Value v; 65 | v.x = 512; 66 | assertEqual(int(v.byte[0]), 0); 67 | assertEqual(int(v.byte[1]), 2); 68 | assertEqual(int(v.byte[2]), 0); 69 | assertEqual(int(v.byte[3]), 0); 70 | } 71 | -------------------------------------------------------------------------------- /test/matrix.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it, console; 4 | 5 | 6 | struct Matrix { 7 | float elements[2][2]; 8 | 9 | static function mul(Matrix * a, Matrix * b, Matrix * c) { 10 | for (let int j = 0; j < 2; j++) { 11 | for (let int k = 0; k < 2; k++) { 12 | for (let int i = 0; i < 2; i++) { 13 | c->elements[i][j] += a->elements[i][k] * b->elements[k][j]; 14 | } 15 | } 16 | } 17 | } 18 | } 19 | 20 | describe('Matrix', function() { 21 | it('Multiply', function () { 22 | let Matrix a, b, c, d; 23 | a.elements[0][0] = 1; 24 | a.elements[0][1] = 2; 25 | a.elements[1][0] = 3; 26 | a.elements[1][1] = 4; 27 | 28 | b.elements[0][0] = 0; 29 | b.elements[0][1] = 0; 30 | b.elements[1][0] = 0; 31 | b.elements[1][1] = 0; 32 | 33 | c.elements[0][0] = 0; 34 | c.elements[0][1] = 0; 35 | c.elements[1][0] = 0; 36 | c.elements[1][1] = 0; 37 | 38 | Matrix.mul(&a, &a, &b); 39 | 40 | assert (b.elements[0][0] === 7); 41 | assert (b.elements[0][1] === 10); 42 | assert (b.elements[1][0] === 15); 43 | assert (b.elements[1][1] === 22); 44 | 45 | Matrix.mul(&a, &b, &c); 46 | 47 | assert (c.elements[0][0] === 37); 48 | assert (c.elements[0][1] === 54); 49 | assert (c.elements[1][0] === 81); 50 | assert (c.elements[1][1] === 118); 51 | 52 | }); 53 | }); 54 | 55 | 56 | describe('Structs', function() { 57 | it('allocates an union', function () { 58 | 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/structs-members.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it, Math; 4 | 5 | struct Point { 6 | int x, y; 7 | function Point (int x, int y) { 8 | this->x = x; 9 | this->y = y; 10 | } 11 | function toString() { 12 | return "{x: " + this->x + ", y: " + this->y + "}"; 13 | } 14 | function distanceTo(Point * other) { 15 | let Line l (this->x, this->y, other->x, other->y); 16 | return l.getLength(); 17 | } 18 | } 19 | 20 | struct Line { 21 | Point a, b; 22 | function Line (int x1, int y1, int x2, int y2) { 23 | this->a.x = x1; 24 | this->a.y = y1; 25 | this->b.x = x2; 26 | this->b.y = y2; 27 | } 28 | function float getLength() { 29 | let float dx = this->a.x - this->b.x; 30 | let float dy = this->a.y - this->b.y; 31 | return float(Math.sqrt(dx * dx + dy * dy)); 32 | } 33 | function toString() { 34 | return "{" + this->a.toString() + " -> " + this->b.toString() + "}"; 35 | } 36 | } 37 | 38 | function floatIsEqual(a, b) { 39 | let d = a - b; 40 | if (d < 0) { 41 | d *= -1; 42 | } 43 | return d < 0.001; 44 | } 45 | 46 | describe('Member Functions', function() { 47 | it('allocates structs on the heap and call methods', function () { 48 | let Point * p = new Point(1, 2); 49 | assert (p->toString() === "{x: 1, y: 2}"); 50 | 51 | let Line * l = new Line(1, 2, 3, 4); 52 | assert (l->toString() === "{{x: 1, y: 2} -> {x: 3, y: 4}}"); 53 | assert (floatIsEqual(l->getLength(), 2.8284271247461903)); 54 | }); 55 | 56 | it('allocates structs on the stack and call methods', function () { 57 | let Line l1 (1, 2, 3, 4), l2 (2, 3, 4, 5), *l3; 58 | assert (l1.toString() === "{{x: 1, y: 2} -> {x: 3, y: 4}}"); 59 | assert (l1.a.toString() === "{x: 1, y: 2}"); 60 | assert (l1.b.toString() === "{x: 3, y: 4}"); 61 | }); 62 | 63 | it('allocates structs on the stack and call methods', function () { 64 | for (let int i = 0; i < 10; i++) { 65 | let Point * k = new Point(1, 2); 66 | assert (k->toString() === "{x: 1, y: 2}"); 67 | } 68 | 69 | for (let int i = 0; i < 10; i++) { 70 | let Point a (i, 1), b (i, 2); 71 | assert (a.distanceTo(&b) === 1); 72 | } 73 | }); 74 | }); -------------------------------------------------------------------------------- /test/structs-static-members.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it, Math; 4 | 5 | struct A { 6 | int x; 7 | } 8 | 9 | struct B { 10 | int x; 11 | static int y; 12 | static function setY(int y) { 13 | this->y = y; 14 | } 15 | } 16 | 17 | describe('Structs with Member Functions', function() { 18 | it('calls static member functions', function () { 19 | for (let int i = 0; i < 10; i++) { 20 | B.setY(i); 21 | assert (B.y === i); 22 | let int * x = &B.y; 23 | *x = i + 1; 24 | assert (B.y === i + 1); 25 | } 26 | }); 27 | it('updates static member fields', function () { 28 | for (let int i = 0; i < 10; i++) { 29 | let int * x = &B.y; 30 | *x = i + 1; 31 | assert (B.y === i + 1); 32 | } 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/structs.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it; 4 | 5 | struct S { 6 | union { 7 | int x; 8 | float y; 9 | } u; 10 | struct { 11 | int x; 12 | float y; 13 | } s; 14 | int x; 15 | }; 16 | 17 | function floatIsEqual(a, b) { 18 | let d = a - b; 19 | if (d < 0) { 20 | d *= -1; 21 | } 22 | return d < 0.001; 23 | } 24 | 25 | describe('Structs', function() { 26 | it('allocates a struct with unions', function () { 27 | let S s; 28 | s.u.x = 5; 29 | s.s.x = 5; 30 | s.s.y = 3.14; 31 | s.x = 10; 32 | 33 | assert (s.u.x === 5); 34 | assert (s.u.y === 7.006492321624085e-45); 35 | assert (s.s.x === 5); 36 | assert (floatIsEqual(s.s.y, 3.14)); 37 | assert (s.x === 10); 38 | }); 39 | }); 40 | 41 | union foo { 42 | int x; 43 | float y; 44 | }; 45 | 46 | struct bar { 47 | foo u; 48 | }; 49 | 50 | describe('Structs', function() { 51 | it('allocates an union', function () { 52 | let foo u; 53 | u.x = 5; 54 | assert (u.x === 5); 55 | assert (floatIsEqual(u.y, 7.006492321624085e-45)); 56 | 57 | let foo *uStar = new foo; 58 | uStar->x = 5; 59 | assert (uStar->x === 5); 60 | assert (floatIsEqual(uStar->y, 7.006492321624085e-45)); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/types.ljs: -------------------------------------------------------------------------------- 1 | let assert = require("assert"); 2 | 3 | extern describe, it; 4 | 5 | describe('Machine Types', function() { 6 | it('u8', function () { 7 | let u8 x; assert (x === 0); 8 | x = 1; assert (x === 1); 9 | x = -1; assert (x === 0xff); 10 | x = 0xff; assert (x === 0xff); 11 | x += 1; assert (x === 0); 12 | assert (sizeof(u8) === 1); 13 | }); 14 | 15 | it('i8', function () { 16 | let i8 x; assert (x === 0); 17 | x = 1; assert (x === 1); 18 | x = -1; assert (x === -1); 19 | x = 0xff; assert (x === -1); 20 | x += 1; assert (x === 0); 21 | assert (sizeof(i8) === 1); 22 | }); 23 | 24 | 25 | it('u16', function () { 26 | let u16 x; assert (x === 0); 27 | x = 1; assert (x === 1); 28 | x = -1; assert (x === 0xffff); 29 | x = 0xffff; assert (x === 0xffff); 30 | x += 1; assert (x === 0); 31 | assert (sizeof(u16) === 2); 32 | }); 33 | 34 | it('i16', function () { 35 | let i16 x; assert (x === 0); 36 | x = 1; assert (x === 1); 37 | x = -1; assert (x === -1); 38 | x = 0xffff; assert (x === -1); 39 | x += 1; assert (x === 0); 40 | assert (sizeof(i16) === 2); 41 | }); 42 | 43 | it('u32', function () { 44 | let u32 x; assert (x === 0); 45 | x = 1; assert (x === 1); 46 | x = -1; assert (x === 0xffffffff); 47 | x = 0xffffffff; assert (x === 0xffffffff); 48 | x += 1; assert (x === 0); 49 | assert (sizeof(u32) === 4); 50 | }); 51 | 52 | it('i32', function () { 53 | let i32 x; assert (x === 0); 54 | x = 1; assert (x === 1); 55 | x = -1; assert (x === -1); 56 | x = 0xffffffff; assert (x === -1); 57 | x += 1; assert (x === 0); 58 | assert (sizeof(i32) === 4); 59 | }); 60 | 61 | }); --------------------------------------------------------------------------------