neutrinoscript
Version:
Like C for Javascript
328 lines (289 loc) • 8.86 kB
HTML
<html>
<head>
<title>LLJS : Low-Level JavaScript</title>
<link rel="stylesheet" type="text/css" href="css/screen.css">
<link rel="stylesheet" href="vendor/cm/lib/codemirror.css">
</head>
<body>
<a href="https://github.com/mbebenita/LLJS"><img style="position: absolute; top: 0; right: 0; border: 0;" src="images/fork.png" alt="Fork me on GitHub"></a>
<a href="http://mozilla.org"><img width="118" height="68" style="position: absolute; top: 0; left: 50; border: 0;" src="images/mozilla.png" alt="Mozilla"></a>
<br>
<div class="container">
<h2>K&R Malloc vs. JS Object Allocation</h2>
<canvas id="canvas-latency" width="640" height="100"></canvas>
<br><br>
<canvas id="canvas" width="640" height="640"></canvas>
<script>
var latency = (function () {
var ctx = document.getElementById('canvas-latency').getContext('2d');
var width = 640;
var height = 100;
var sampleWidth = 4
var sampleCount = width / (sampleWidth + 1);
var last = null;
var samples = [];
var max = 0;
function computeStandardDeviation(x) {
var a = 0, b = 0, n = x.length;
for (var i = 0; i < n; i++) {
a += x[i] * x[i];
b += x[i];
}
return Math.sqrt(a / n - (b / n) * (b / n));
}
return {
tick: function () {
var curr = new Date();
if (last) {
if (samples.length > sampleCount) {
samples.shift();
}
samples.push(curr - last);
ctx.clearRect(0, 0, 640, 100);
var sum = 0;
for (var i = 0; i < samples.length; i++) {
sum += samples[i];
max = Math.max(max, samples[i]);
}
var avg = sum / samples.length;
for (var i = 0; i < samples.length; i++) {
var scaledSample = (samples[i] / max);
ctx.fillRect(i * (sampleWidth + 1), 100, sampleWidth, - scaledSample * (height - 30));
}
ctx.font = "Bold 10pt Verdana";
ctx.fillText("fps: " + (1000 / avg).toFixed(2) + ", std: " + computeStandardDeviation(samples).toFixed(2), 0, 25);
}
last = curr;
}
};
})();
var cancelAnimationFrame = ( function() {
return window.cancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
clearTimeout
} )();
var requestAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
return window.setTimeout(callback, 1000 / 60);
};
})();
</script>
<pre class="example">
const int n = 250000; // Number of object allocations.
const int m = 300; // Number of balls.
function drawHook() {
benchObject();
// benchStruct();
}
extern document, window, Math, Date, trace, latency, cancelAnimationFrame, requestAnimationFrame;
let balls = [];
let radius = 10, width = 640, height = 640;
for (let i = 0; i < m; i++) {
let dx = 0.5 - Math.random();
let dy = 0.5 - Math.random();
balls.push({x: width / 2, y: height / 2, dx: dx, dy: dy, radius: 5 + Math.random() * 5});
}
let ctx = document.getElementById('canvas').getContext('2d');
struct Node {
Node *next;
int val;
double pad1, pad2, pad3, pad4;
};
function ObjNode() {
this.next = null;
this.val = 0;
this.pad1 = 0;
this.pad2 = 0;
this.pad3 = 0;
this.pad4 = 0;
}
function benchStruct() {
let Node *head;
for (let int i = 0; i < n; ++i) {
let Node *prev = head;
head = new Node;
head->next = prev;
head->val = i;
}
let double sum = 0;
for (let int i = 0; i < n; ++i) {
let Node *prev = head;
sum += head->val;
head = head->next;
delete prev;
}
}
function benchObject() {
let head;
for (let i = 0; i < n; ++i) {
let prev = head;
head = new ObjNode();
head.next = prev;
head.val = i;
}
let sum = 0;
for (let i = 0; i < n; ++i) {
sum += head.val;
head = head.next;
}
}
let last = new Date();
let request;
function draw() {
latency.tick();
ctx.clearRect(0, 0, width, height);
drawHook();
let curr = new Date();
let elapsed = (curr - last) / 10;
last = curr;
for (let i = 0; i < balls.length; i++) {
let ball = balls[i];
let dx = ball.dx * elapsed;
let dy = ball.dy * elapsed;
let nx = ball.x + dx;
let ny = ball.y + dy;
if (nx < ball.radius || nx > width - ball.radius) {
ball.dx *= -1;
dx *= -1;
}
if (ny < ball.radius || ny > height - ball.radius) {
ball.dy *= -1;
dy *= -1;
}
ball.x += dx;
ball.y += dy;
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
request = requestAnimationFrame(draw);
}
if (request) {
cancelAnimationFrame(request);
}
draw();
</pre>
</div>
<script src="vendor/cm/lib/codemirror.js"></script>
<script src="vendor/cm/mode/javascript/javascript.js"></script>
<script src="vendor/jquery-1.7.2.min.js"></script>
<script src="lljs/estransform.js"></script>
<script src="lljs/types.js"></script>
<script src="lljs/util.js"></script>
<script src="lljs/scope.js"></script>
<script src="lljs/esprima.js"></script>
<script src="lljs/escodegen.js"></script>
<script src="lljs/compiler.js"></script>
<script src="lljs/memcheck.js"></script>
<script src="lljs/memory.js"></script>
<script src="lljs/ljc.js"></script>
<script>
var id = 0;
$('.example').replaceWith(function() {
var src = this.innerHTML;
var lineCount = src.split("\n").length;
return '<table class="example"><tr><td><textarea id="ex:' + id + ':source" class="jcCode" rows="' + lineCount + '" spellcheck="false">' + src + '</textarea></td><td valign="top"><pre id="ex:' + id++ + ':result" class="jcResult"></pre></td></tr></table>'
});
var lastMarker;
function compileExample(ex) {
if (lastMarker) {
this.clearMarker(lastMarker);
}
var number = ex.split(":")[1];
var result = document.getElementById("ex:" + number + ":result");
try {
var name;
if (Number(number) === id - 1) {
name = "memory";
} else {
name = "ex" + number;
}
result.innerHTML = LJC.compile(name, name, this.getValue(), { bare: true });
} catch (x) {
result.innerHTML = x.message;
if (x.lineNumber) {
lastMarker = this.setMarker(x.lineNumber - 1, "<span style=\"color: #900\">x</span> %N%");
}
}
}
var Timer = (function () {
function timer() {
this.name = null;
this.start = null;
}
timer.prototype.begin = function (name) {
if (this.start) {
if (this.name) {
trace("Timer: " + (new Date() - this.start) + " ms: " + this.name);
} else {
trace("Timer: " + (new Date() - this.start) + " ms.");
}
}
this.start = new Date();
this.name = name;
};
return timer;
})();
var timer;
var trace;
function require(name) {
if (name === "memory") {
return memory;
}
return null;
}
function executeExample(id) {
var number = id.split(":")[1];
var result = document.getElementById("ex:" + number + ":result");
try {
memory.reset();
timer = new Timer();
result.innerHTML = "";
trace = function (x) {
result.innerHTML += x + "\n";
};
start = new Date();
var code = LJC.compile("ex" + number, "ex" + number, this.getValue(), {});
result.innerHTML += "Compiled in: " + (new Date() - start) + " ms\n";
result.innerHTML += "-----------------------------------------------------\n";
start = new Date();
new Function(code)();
timer.begin(null);
result.innerHTML += "-----------------------------------------------------\n";
result.innerHTML += "Executed in : " + (new Date() - start) + " ms.";
} catch (x) {
result.innerHTML = x.message;
}
}
$('.jcCode').each(function() {
var id = this.id;
var cm = CodeMirror.fromTextArea(this, {
tabSize: 2,
lineNumbers: true,
gutter: true,
onChange: function () {
compileExample.call(cm, id);
},
extraKeys: {
"Ctrl-Enter": function () {
executeExample.call(cm, id);
},
"Cmd-Enter": function () {
executeExample.call(cm, id);
}
}
});
compileExample.call(cm, id);
});
</script>
</body>
</html>