From 76e2228c25b2b5a2911e97116d0558918772ded4 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Thu, 19 Jun 2014 11:41:15 +0100 Subject: [PATCH 01/60] Support webkit gamepad api --- src/library_html5.js | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/library_html5.js b/src/library_html5.js index d5d0cd6637a9c..a091b81fe4b94 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -765,10 +765,18 @@ var LibraryJSEvents = { {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.axis, 'e.axes[i]', 'double') }}}; } for(var i = 0; i < e.buttons.length; ++i) { - {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}}; + if (typeof(e.buttons[i]) === 'object') { + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}}; + } else { + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i]', 'double') }}}; + } } for(var i = 0; i < e.buttons.length; ++i) { - {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i32') }}}; + if (typeof(e.buttons[i]) === 'object') { + {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i32') }}}; + } else { + {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i] == 1.0', 'i32') }}}; + } } {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.connected, 'e.connected', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.index, 'e.index', 'i32') }}}; @@ -1248,26 +1256,43 @@ var LibraryJSEvents = { }, emscripten_set_gamepadconnected_callback: function(userData, useCapture, callbackfunc) { - if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; JSEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADCONNECTED') }}}, "gamepadconnected"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_gamepaddisconnected_callback: function(userData, useCapture, callbackfunc) { - if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; JSEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED') }}}, "gamepaddisconnected"); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_get_num_gamepads: function() { - if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - return navigator.getGamepads().length; + if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (navigator.getGamepads) { + return navigator.getGamepads().length; + } else if (navigator.webkitGetGamepads) { + var gamepads = navigator.webkitGetGamepads(); + + for (var i = 0; i < gamepads.length; i++) { + if (typeof gamepads[i] === 'undefined') { + return i; + } + } + + return gamepads.length; + } }, emscripten_get_gamepad_status: function(index, gamepadState) { - if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - var gamepads = navigator.getGamepads(); - if (index < 0 || index >= gamepads.length) { + if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + var gamepads; + if (navigator.getGamepads) { + gamepads = navigator.getGamepads(); + } else if (navigator.webkitGetGamepads) { + gamepads = navigator.webkitGetGamepads(); + } + if (index < 0 || index >= gamepads.length || typeof gamepads[index] === 'undefined') { return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; } JSEvents.fillGamepadEventData(gamepadState, gamepads[index]); From 948fae299a031d8a0e373bc9c526a46667ec2951 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Mon, 30 Jun 2014 17:27:27 +0100 Subject: [PATCH 02/60] Review changes --- src/library_html5.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/library_html5.js b/src/library_html5.js index a091b81fe4b94..fdc11ec4ba4c4 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -1272,15 +1272,7 @@ var LibraryJSEvents = { if (navigator.getGamepads) { return navigator.getGamepads().length; } else if (navigator.webkitGetGamepads) { - var gamepads = navigator.webkitGetGamepads(); - - for (var i = 0; i < gamepads.length; i++) { - if (typeof gamepads[i] === 'undefined') { - return i; - } - } - - return gamepads.length; + return navigator.webkitGetGamepads().length; } }, @@ -1292,9 +1284,12 @@ var LibraryJSEvents = { } else if (navigator.webkitGetGamepads) { gamepads = navigator.webkitGetGamepads(); } - if (index < 0 || index >= gamepads.length || typeof gamepads[index] === 'undefined') { + if (index < 0 || index >= gamepads.length) { return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; } + if (typeof gamepads[index] === 'undefined') { + return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + } JSEvents.fillGamepadEventData(gamepadState, gamepads[index]); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, From 627141c776b58b9bba82000d0bf10fde7571af97 Mon Sep 17 00:00:00 2001 From: Ningxin Hu Date: Mon, 18 Aug 2014 14:55:24 -0700 Subject: [PATCH 03/60] Update the simd.js It is based on version https://github.com/johnmccutchan/ecmascript_simd/blob/14aa231d3c1021695ecee467ef35e5d61c8c669e/src/ecmascript_simd.js Changes: 46620fd Add type check into SIMD operations. 1f29859 Fix float64x2.clamp implementation and add test case for it. 22b8ccf Use object properties instead of typed array as storage in polyfill 8941215 Changed conversion operators from SIMD.XXX.toYYY() to SIMD.YYY.fromXXX(), added 'select' operator for all types, added/updated tests 3eaaf69 Added reciprocal, reciprocalSqrt, shuffle, shuffleMix, comparison, and select operators to SIMD.float64x2 6f68238 Added SIMD.float64x2 (abs, neg, add, sub, mul, div, clamp, min, max, scale, sqrt, withX, withY, SIMD.float32x4.toFloat64x2) --- src/simd.js | 809 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 715 insertions(+), 94 deletions(-) diff --git a/src/simd.js b/src/simd.js index d5ff8b156b4be..1269cbdd4e27f 100644 --- a/src/simd.js +++ b/src/simd.js @@ -25,6 +25,48 @@ // SIMD module. var SIMD = {}; +// private stuff. +var _PRIVATE = {} + +_PRIVATE._f32 = new Float32Array(1); +_PRIVATE._i32 = new Int32Array(1); + +_PRIVATE._f32x4 = new Float32Array(4); +_PRIVATE._f64x2 = new Float64Array(_PRIVATE._f32x4.buffer); +_PRIVATE._i32x4 = new Int32Array(_PRIVATE._f32x4.buffer); + +_PRIVATE._f32x8 = new Float32Array(8); +_PRIVATE._f64x4 = new Float64Array(4); +_PRIVATE._i32x8 = new Int32Array(8); + +_PRIVATE.truncatef32 = function(x) { + _PRIVATE._f32[0] = x; + return _PRIVATE._f32[0]; +} + +_PRIVATE.truncatei32 = function(x) { + _PRIVATE._i32[0] = x; + return _PRIVATE._i32[0]; +} + +function checkFloat32x4(t) { + if (!(t instanceof SIMD.float32x4)) { + throw new TypeError("argument is not a float32x4."); + } +} + +function checkFloat64x2(t) { + if (!(t instanceof SIMD.float64x2)) { + throw new TypeError("argument is not a float64x2."); + } +} + +function checkInt32x4(t) { + if (!(t instanceof SIMD.int32x4)) { + throw new TypeError("argument is not a int32x4."); + } +} + /** * Construct a new instance of float32x4 number. * @param {double} value used for x lane. @@ -37,11 +79,10 @@ SIMD.float32x4 = function(x, y, z, w) { if (!(this instanceof SIMD.float32x4)) { return new SIMD.float32x4(x, y, z, w); } - this.storage_ = new Float32Array(4); - this.storage_[0] = x; - this.storage_[1] = y; - this.storage_[2] = z; - this.storage_[3] = w; + this.x_ = _PRIVATE.truncatef32(x); + this.y_ = _PRIVATE.truncatef32(y); + this.z_ = _PRIVATE.truncatef32(z); + this.w_ = _PRIVATE.truncatef32(w); } /** @@ -62,6 +103,141 @@ SIMD.float32x4.splat = function(s) { return SIMD.float32x4(s, s, s, s); } +/** + * @param {float64x2} t An instance of float64x2. + * @return {float32x4} A float32x4 with .x and .y from t + */ +SIMD.float32x4.fromFloat64x2 = function(t) { + checkFloat64x2(t); + var a = SIMD.float32x4.zero(); + a.x_ = t.x_; + a.y_ = t.y_; + return a; +} + +/** + * @param {int32x4} t An instance of int32x4. + * @return {float32x4} A float to integer conversion copy of t. + */ +SIMD.float32x4.fromInt32x4 = function(t) { + checkInt32x4(t); + var a = SIMD.float32x4.zero(); + a.x_ = t.x_; + a.y_ = t.y_; + a.z_ = t.z_; + a.w_ = t.w_; + return a; +} + +/** + * @param {float64x2} t An instance of float64x2. + * @return {float32x4} a bit-wise copy of t as a float32x4. + */ +SIMD.float32x4.fromFloat64x2Bits = function(t) { + checkFloat64x2(t); + _PRIVATE._f64x2[0] = t.x_; + _PRIVATE._f64x2[1] = t.y_; + return SIMD.float32x4(_PRIVATE._f32x4[0], + _PRIVATE._f32x4[1], + _PRIVATE._f32x4[2], + _PRIVATE._f32x4[3]); +} + +/** + * @param {int32x4} t An instance of int32x4. + * @return {float32x4} a bit-wise copy of t as a float32x4. + */ +SIMD.float32x4.fromInt32x4Bits = function(t) { + checkInt32x4(t); + _PRIVATE._i32x4[0] = t.x_; + _PRIVATE._i32x4[1] = t.y_; + _PRIVATE._i32x4[2] = t.z_; + _PRIVATE._i32x4[3] = t.w_; + return SIMD.float32x4(_PRIVATE._f32x4[0], + _PRIVATE._f32x4[1], + _PRIVATE._f32x4[2], + _PRIVATE._f32x4[3]); +} + +/** + * Construct a new instance of float64x2 number. + * @param {double} value used for x lane. + * @param {double} value used for y lane. + * @constructor + */ +SIMD.float64x2 = function(x, y) { + if (!(this instanceof SIMD.float64x2)) { + return new SIMD.float64x2(x, y); + } + this.x_ = x; + this.y_ = y; +} + +/** + * Construct a new instance of float64x2 number with 0.0 in all lanes. + * @constructor + */ +SIMD.float64x2.zero = function() { + return SIMD.float64x2(0.0, 0.0); +} + +/** + * Construct a new instance of float64x2 number with the same value + * in all lanes. + * @param {double} value used for all lanes. + * @constructor + */ +SIMD.float64x2.splat = function(s) { + return SIMD.float32x4(s, s); +} + +/** + * @param {float32x4} t An instance of float32x4. + * @return {float64x2} A float64x2 with .x and .y from t + */ +SIMD.float64x2.fromFloat32x4 = function(t) { + checkFloat32x4(t); + var a = SIMD.float64x2(t.x_, t.y_); + return a; +} + +/** + * @param {int32x4} t An instance of int32x4. + * @return {float64x2} A float64x2 with .x and .y from t + */ +SIMD.float64x2.fromInt32x4 = function(t) { + checkInt32x4(t); + var a = SIMD.float64x2.zero(); + a.x_ = t.x_; + a.y_ = t.y_; + return a; +} + +/** + * @param {float32x4} t An instance of float32x4. + * @return {float64x2} a bit-wise copy of t as a float64x2. + */ +SIMD.float64x2.fromFloat32x4Bits = function(t) { + checkFloat32x4(t); + _PRIVATE._f32x4[0] = t.x_; + _PRIVATE._f32x4[1] = t.y_; + _PRIVATE._f32x4[2] = t.z_; + _PRIVATE._f32x4[3] = t.w_; + return SIMD.float64x2(_PRIVATE._f64x2[0], _PRIVATE._f64x2[1]); +} + +/** + * @param {int32x4} t An instance of int32x4. + * @return {float64x2} a bit-wise copy of t as a float64x2. + */ +SIMD.float64x2.fromInt32x4Bits = function(t) { + checkInt32x4(t); + _PRIVATE._i32x4[0] = t.x_; + _PRIVATE._i32x4[1] = t.y_; + _PRIVATE._i32x4[2] = t.z_; + _PRIVATE._i32x4[3] = t.w_; + return SIMD.float64x2(_PRIVATE._f64x2[0], _PRIVATE._f64x2[1]); +} /** * Construct a new instance of int32x4 number. @@ -75,11 +251,10 @@ SIMD.int32x4 = function(x, y, z, w) { if (!(this instanceof SIMD.int32x4)) { return new SIMD.int32x4(x, y, z, w); } - this.storage_ = new Int32Array(4); - this.storage_[0] = x; - this.storage_[1] = y; - this.storage_[2] = z; - this.storage_[3] = w; + this.x_ = _PRIVATE.truncatei32(x); + this.y_ = _PRIVATE.truncatei32(y); + this.z_ = _PRIVATE.truncatei32(z); + this.w_ = _PRIVATE.truncatei32(w); } /** @@ -116,11 +291,62 @@ SIMD.int32x4.splat = function(s) { return SIMD.int32x4(s, s, s, s); } +/** + * @param {float32x4} t An instance of float32x4. + * @return {int32x4} with a integer to float conversion of t. + */ +SIMD.int32x4.fromFloat32x4 = function(t) { + checkFloat32x4(t); + var a = SIMD.int32x4(Math.floor(t.x_), Math.floor(t.y_), + Math.floor(t.z_), Math.floor(t.w_)); + return a; +} + +/** + * @param {float64x2} t An instance of float64x2. + * @return {int32x4} An int32x4 with .x and .y from t + */ +SIMD.int32x4.fromFloat64x2 = function(t) { + checkFloat64x2(t); + var a = SIMD.int32x4.zero(); + a.x_ = Math.floor(t.x_); + a.y_ = Math.floor(t.y_); + return a; +} + +/** + * @param {float32x4} t An instance of float32x4. + * @return {int32x4} a bit-wise copy of t as a int32x4. + */ +SIMD.int32x4.fromFloat32x4Bits = function(t) { + checkFloat32x4(t); + _PRIVATE._f32x4[0] = t.x_; + _PRIVATE._f32x4[1] = t.y_; + _PRIVATE._f32x4[2] = t.z_; + _PRIVATE._f32x4[3] = t.w_; + var alias = _PRIVATE._i32x4; + return SIMD.int32x4(alias[0], alias[1], alias[2], alias[3]); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @return {int32x4} a bit-wise copy of t as an int32x4. + */ +SIMD.int32x4.fromFloat64x2Bits = function(t) { + checkFloat64x2(t); + _PRIVATE._f64x2[0] = t.x_; + _PRIVATE._f64x2[1] = t.y_; + var alias = _PRIVATE._i32x4; + var ix4 = SIMD.int32x4(alias[0], alias[1], alias[2], alias[3]); + return ix4; +} + /** * @return {float32x4} New instance of float32x4 with absolute values of * t. */ SIMD.float32x4.abs = function(t) { + checkFloat32x4(t); return SIMD.float32x4(Math.abs(t.x), Math.abs(t.y), Math.abs(t.z), Math.abs(t.w)); } @@ -130,6 +356,7 @@ SIMD.float32x4.abs = function(t) { * t. */ SIMD.float32x4.neg = function(t) { + checkFloat32x4(t); return SIMD.float32x4(-t.x, -t.y, -t.z, -t.w); } @@ -137,6 +364,8 @@ SIMD.float32x4.neg = function(t) { * @return {float32x4} New instance of float32x4 with a + b. */ SIMD.float32x4.add = function(a, b) { + checkFloat32x4(a); + checkFloat32x4(b); return SIMD.float32x4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } @@ -144,6 +373,8 @@ SIMD.float32x4.add = function(a, b) { * @return {float32x4} New instance of float32x4 with a - b. */ SIMD.float32x4.sub = function(a, b) { + checkFloat32x4(a); + checkFloat32x4(b); return SIMD.float32x4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } @@ -151,6 +382,8 @@ SIMD.float32x4.sub = function(a, b) { * @return {float32x4} New instance of float32x4 with a * b. */ SIMD.float32x4.mul = function(a, b) { + checkFloat32x4(a); + checkFloat32x4(b); return SIMD.float32x4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } @@ -158,6 +391,8 @@ SIMD.float32x4.mul = function(a, b) { * @return {float32x4} New instance of float32x4 with a / b. */ SIMD.float32x4.div = function(a, b) { + checkFloat32x4(a); + checkFloat32x4(b); return SIMD.float32x4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); } @@ -166,6 +401,7 @@ SIMD.float32x4.div = function(a, b) { * between lowerLimit and upperLimit. */ SIMD.float32x4.clamp = function(t, lowerLimit, upperLimit) { + checkFloat32x4(t); var cx = t.x < lowerLimit.x ? lowerLimit.x : t.x; var cy = t.y < lowerLimit.y ? lowerLimit.y : t.y; var cz = t.z < lowerLimit.z ? lowerLimit.z : t.z; @@ -182,6 +418,7 @@ SIMD.float32x4.clamp = function(t, lowerLimit, upperLimit) { * t and other. */ SIMD.float32x4.min = function(t, other) { + checkFloat32x4(t); var cx = t.x > other.x ? other.x : t.x; var cy = t.y > other.y ? other.y : t.y; var cz = t.z > other.z ? other.z : t.z; @@ -194,6 +431,7 @@ SIMD.float32x4.min = function(t, other) { * t and other. */ SIMD.float32x4.max = function(t, other) { + checkFloat32x4(t); var cx = t.x < other.x ? other.x : t.x; var cy = t.y < other.y ? other.y : t.y; var cz = t.z < other.z ? other.z : t.z; @@ -206,6 +444,7 @@ SIMD.float32x4.max = function(t, other) { * t. */ SIMD.float32x4.reciprocal = function(t) { + checkFloat32x4(t); return SIMD.float32x4(1.0 / t.x, 1.0 / t.y, 1.0 / t.z, 1.0 / t.w); } @@ -214,14 +453,17 @@ SIMD.float32x4.reciprocal = function(t) { * reciprocal value of t. */ SIMD.float32x4.reciprocalSqrt = function(t) { + checkFloat32x4(t); return SIMD.float32x4(Math.sqrt(1.0 / t.x), Math.sqrt(1.0 / t.y), Math.sqrt(1.0 / t.z), Math.sqrt(1.0 / t.w)); } + /** * @return {float32x4} New instance of float32x4 with values of t * scaled by s. */ SIMD.float32x4.scale = function(t, s) { + checkFloat32x4(t); return SIMD.float32x4(s * t.x, s * t.y, s * t.z, s * t.w); } @@ -230,6 +472,7 @@ SIMD.float32x4.scale = function(t, s) { * values of t. */ SIMD.float32x4.sqrt = function(t) { + checkFloat32x4(t); return SIMD.float32x4(Math.sqrt(t.x), Math.sqrt(t.y), Math.sqrt(t.z), Math.sqrt(t.w)); } @@ -240,12 +483,17 @@ SIMD.float32x4.sqrt = function(t) { * @return {float32x4} New instance of float32x4 with lanes shuffled. */ SIMD.float32x4.shuffle = function(t, mask) { + checkFloat32x4(t); var _x = (mask) & 0x3; var _y = (mask >> 2) & 0x3; var _z = (mask >> 4) & 0x3; var _w = (mask >> 6) & 0x3; - return SIMD.float32x4(t.storage_[_x], t.storage_[_y], t.storage_[_z], - t.storage_[_w]); + _PRIVATE._f32x4[0] = t.x_; + _PRIVATE._f32x4[1] = t.y_; + _PRIVATE._f32x4[2] = t.z_; + _PRIVATE._f32x4[3] = t.w_; + var storage = _PRIVATE._f32x4; + return SIMD.float32x4(storage[_x], storage[_y], storage[_z], storage[_w]); } /** @@ -255,12 +503,23 @@ SIMD.float32x4.shuffle = function(t, mask) { * @return {float32x4} New instance of float32x4 with lanes shuffled. */ SIMD.float32x4.shuffleMix = function(t1, t2, mask) { + checkFloat32x4(t1); + checkFloat32x4(t2); var _x = (mask) & 0x3; var _y = (mask >> 2) & 0x3; var _z = (mask >> 4) & 0x3; var _w = (mask >> 6) & 0x3; - return SIMD.float32x4(t1.storage_[_x], t1.storage_[_y], t2.storage_[_z], - t2.storage_[_w]); + var storage = _PRIVATE._f32x8; + storage[0] = t1.x_; + storage[1] = t1.y_; + storage[2] = t1.z_; + storage[3] = t1.w_; + storage[4] = t2.x_; + storage[5] = t2.y_; + storage[6] = t2.z_; + storage[7] = t2.w_; + return SIMD.float32x4(storage[0 + _x], storage[0 + _y], + storage[4 + _z], storage[4 + _w]); } /** @@ -269,6 +528,7 @@ SIMD.float32x4.shuffleMix = function(t1, t2, mask) { * x replaced with {x}. */ SIMD.float32x4.withX = function(t, x) { + checkFloat32x4(t); return SIMD.float32x4(x, t.y, t.z, t.w); } @@ -278,6 +538,7 @@ SIMD.float32x4.withX = function(t, x) { * y replaced with {y}. */ SIMD.float32x4.withY = function(t, y) { + checkFloat32x4(t); return SIMD.float32x4(t.x, y, t.z, t.w); } @@ -287,6 +548,7 @@ SIMD.float32x4.withY = function(t, y) { * z replaced with {z}. */ SIMD.float32x4.withZ = function(t, z) { + checkFloat32x4(t); return SIMD.float32x4(t.x, t.y, z, t.w); } @@ -296,6 +558,7 @@ SIMD.float32x4.withZ = function(t, z) { * w replaced with {w}. */ SIMD.float32x4.withW = function(t, w) { + checkFloat32x4(t); return SIMD.float32x4(t.x, t.y, t.z, w); } @@ -306,6 +569,8 @@ SIMD.float32x4.withW = function(t, w) { * the result of t < other. */ SIMD.float32x4.lessThan = function(t, other) { + checkFloat32x4(t); + checkFloat32x4(other); var cx = t.x < other.x; var cy = t.y < other.y; var cz = t.z < other.z; @@ -320,6 +585,8 @@ SIMD.float32x4.lessThan = function(t, other) { * the result of t <= other. */ SIMD.float32x4.lessThanOrEqual = function(t, other) { + checkFloat32x4(t); + checkFloat32x4(other); var cx = t.x <= other.x; var cy = t.y <= other.y; var cz = t.z <= other.z; @@ -334,6 +601,8 @@ SIMD.float32x4.lessThanOrEqual = function(t, other) { * the result of t == other. */ SIMD.float32x4.equal = function(t, other) { + checkFloat32x4(t); + checkFloat32x4(other); var cx = t.x == other.x; var cy = t.y == other.y; var cz = t.z == other.z; @@ -348,6 +617,8 @@ SIMD.float32x4.equal = function(t, other) { * the result of t != other. */ SIMD.float32x4.notEqual = function(t, other) { + checkFloat32x4(t); + checkFloat32x4(other); var cx = t.x != other.x; var cy = t.y != other.y; var cz = t.z != other.z; @@ -362,6 +633,8 @@ SIMD.float32x4.notEqual = function(t, other) { * the result of t >= other. */ SIMD.float32x4.greaterThanOrEqual = function(t, other) { + checkFloat32x4(t); + checkFloat32x4(other); var cx = t.x >= other.x; var cy = t.y >= other.y; var cz = t.z >= other.z; @@ -376,6 +649,8 @@ SIMD.float32x4.greaterThanOrEqual = function(t, other) { * the result of t > other. */ SIMD.float32x4.greaterThan = function(t, other) { + checkFloat32x4(t); + checkFloat32x4(other); var cx = t.x > other.x; var cy = t.y > other.y; var cz = t.z > other.z; @@ -384,22 +659,23 @@ SIMD.float32x4.greaterThan = function(t, other) { } /** - * @param {float32x4} t An instance of float32x4. - * @return {int32x4} a bit-wise copy of t as a int32x4. + * @param {int32x4} t Selector mask. An instance of int32x4 + * @param {float32x4} trueValue Pick lane from here if corresponding + * selector lane is 0xFFFFFFFF + * @param {float32x4} falseValue Pick lane from here if corresponding + * selector lane is 0x0 + * @return {float32x4} Mix of lanes from trueValue or falseValue as + * indicated */ -SIMD.float32x4.bitsToInt32x4 = function(t) { - var alias = new Int32Array(t.storage_.buffer); - return SIMD.int32x4(alias[0], alias[1], alias[2], alias[3]); -} - -/** - * @param {float32x4} t An instance of float32x4. - * @return {int32x4} with a integer to float conversion of t. - */ -SIMD.float32x4.toInt32x4 = function(t) { - var a = SIMD.int32x4(t.storage_[0], t.storage_[1], t.storage_[2], - t.storage_[3]); - return a; +SIMD.float32x4.select = function(t, trueValue, falseValue) { + checkInt32x4(t); + checkFloat32x4(trueValue); + checkFloat32x4(falseValue); + var tv = SIMD.int32x4.fromFloat32x4Bits(trueValue); + var fv = SIMD.int32x4.fromFloat32x4Bits(falseValue); + var tr = SIMD.int32x4.and(t, tv); + var fr = SIMD.int32x4.and(SIMD.int32x4.not(t), fv); + return SIMD.float32x4.fromInt32x4Bits(SIMD.int32x4.or(tr, fr)); } /** @@ -408,9 +684,11 @@ SIMD.float32x4.toInt32x4 = function(t) { * @return {float32x4} New instance of float32x4 with values of a & b. */ SIMD.float32x4.and = function(a, b) { - var aInt = SIMD.float32x4.bitsToInt32x4(a); - var bInt = SIMD.float32x4.bitsToInt32x4(b); - return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(aInt, bInt)); + checkFloat32x4(a); + checkFloat32x4(b); + var aInt = SIMD.int32x4.fromFloat32x4Bits(a); + var bInt = SIMD.int32x4.fromFloat32x4Bits(b); + return SIMD.float32x4.fromInt32x4Bits(SIMD.int32x4.and(aInt, bInt)); } /** @@ -419,9 +697,11 @@ SIMD.float32x4.and = function(a, b) { * @return {float32x4} New instance of float32x4 with values of a | b. */ SIMD.float32x4.or = function(a, b) { - var aInt = SIMD.float32x4.bitsToInt32x4(a); - var bInt = SIMD.float32x4.bitsToInt32x4(b); - return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(aInt, bInt)); + checkFloat32x4(a); + checkFloat32x4(b); + var aInt = SIMD.int32x4.fromFloat32x4Bits(a); + var bInt = SIMD.int32x4.fromFloat32x4Bits(b); + return SIMD.float32x4.fromInt32x4Bits(SIMD.int32x4.or(aInt, bInt)); } /** @@ -430,9 +710,11 @@ SIMD.float32x4.or = function(a, b) { * @return {float32x4} New instance of float32x4 with values of a ^ b. */ SIMD.float32x4.xor = function(a, b) { - var aInt = SIMD.float32x4.bitsToInt32x4(a); - var bInt = SIMD.float32x4.bitsToInt32x4(b); - return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(aInt, bInt)); + checkFloat32x4(a); + checkFloat32x4(b); + var aInt = SIMD.int32x4.fromFloat32x4Bits(a); + var bInt = SIMD.int32x4.fromFloat32x4Bits(b); + return SIMD.float32x4.fromInt32x4Bits(SIMD.int32x4.xor(aInt, bInt)); } /** @@ -440,8 +722,294 @@ SIMD.float32x4.xor = function(a, b) { * @return {float32x4} New instance of float32x4 with values of ~a. */ SIMD.float32x4.not = function(a) { - var aInt = SIMD.float32x4.bitsToInt32x4(a); - return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.not(aInt)); + checkFloat32x4(a); + var aInt = SIMD.int32x4.fromFloat32x4Bits(a); + return SIMD.float32x4.fromInt32x4Bits(SIMD.int32x4.not(aInt)); +} + +/** +* @return {float64x2} New instance of float64x2 with absolute values of +* t. +*/ +SIMD.float64x2.abs = function(t) { + checkFloat64x2(t); + return SIMD.float64x2(Math.abs(t.x), Math.abs(t.y)); +} + +/** + * @return {float64x2} New instance of float64x2 with negated values of + * t. + */ +SIMD.float64x2.neg = function(t) { + checkFloat64x2(t); + return SIMD.float64x2(-t.x, -t.y); +} + +/** + * @return {float64x2} New instance of float64x2 with a + b. + */ +SIMD.float64x2.add = function(a, b) { + checkFloat64x2(a); + checkFloat64x2(b); + return SIMD.float64x2(a.x + b.x, a.y + b.y); +} + +/** + * @return {float64x2} New instance of float64x2 with a - b. + */ +SIMD.float64x2.sub = function(a, b) { + checkFloat64x2(a); + checkFloat64x2(b); + return SIMD.float64x2(a.x - b.x, a.y - b.y); +} + +/** + * @return {float64x2} New instance of float64x2 with a * b. + */ +SIMD.float64x2.mul = function(a, b) { + checkFloat64x2(a); + checkFloat64x2(b); + return SIMD.float64x2(a.x * b.x, a.y * b.y); +} + +/** + * @return {float64x2} New instance of float64x2 with a / b. + */ +SIMD.float64x2.div = function(a, b) { + checkFloat64x2(a); + checkFloat64x2(b); + return SIMD.float64x2(a.x / b.x, a.y / b.y); +} + +/** + * @return {float64x2} New instance of float64x2 with t's values clamped + * between lowerLimit and upperLimit. + */ +SIMD.float64x2.clamp = function(t, lowerLimit, upperLimit) { + checkFloat64x2(t); + var cx = t.x < lowerLimit.x ? lowerLimit.x : t.x; + var cy = t.y < lowerLimit.y ? lowerLimit.y : t.y; + cx = cx > upperLimit.x ? upperLimit.x : cx; + cy = cy > upperLimit.y ? upperLimit.y : cy; + return SIMD.float64x2(cx, cy); +} + +/** + * @return {float64x2} New instance of float64x2 with the minimum value of + * t and other. + */ +SIMD.float64x2.min = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x > other.x ? other.x : t.x; + var cy = t.y > other.y ? other.y : t.y; + return SIMD.float64x2(cx, cy); +} + +/** + * @return {float64x2} New instance of float64x2 with the maximum value of + * t and other. + */ +SIMD.float64x2.max = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x < other.x ? other.x : t.x; + var cy = t.y < other.y ? other.y : t.y; + return SIMD.float64x2(cx, cy); +} + +/** + * @return {float64x2} New instance of float64x2 with reciprocal value of + * t. + */ +SIMD.float64x2.reciprocal = function(t) { + checkFloat64x2(t); + return SIMD.float64x2(1.0 / t.x, 1.0 / t.y); +} + +/** + * @return {float64x2} New instance of float64x2 with square root of the + * reciprocal value of t. + */ +SIMD.float64x2.reciprocalSqrt = function(t) { + checkFloat64x2(t); + return SIMD.float64x2(Math.sqrt(1.0 / t.x), Math.sqrt(1.0 / t.y)); +} + +/** + * @return {float64x2} New instance of float32x4 with values of t + * scaled by s. + */ +SIMD.float64x2.scale = function(t, s) { + checkFloat64x2(t); + return SIMD.float64x2(s * t.x, s * t.y); +} + +/** + * @return {float64x2} New instance of float32x4 with square root of + * values of t. + */ +SIMD.float64x2.sqrt = function(t) { + checkFloat64x2(t); + return SIMD.float64x2(Math.sqrt(t.x), Math.sqrt(t.y)); +} + +/** + * @param {float64x2} t An instance of float64x2 to be shuffled. + * @param {integer} mask One of the 4 shuffle masks, for example, SIMD.XY. + * @return {float64x2} New instance of float64x2 with lanes shuffled. + */ +SIMD.float64x2.shuffle = function(t, mask) { + checkFloat64x2(t); + var _x = (mask) & 0x1; + var _y = (mask >> 1) & 0x1; + var storage = _PRIVATE._f64x2; + storage[0] = t.x_; + storage[1] = t.y_; + return SIMD.float64x2(storage[_x], storage[_y]); +} + +/** + * @param {float64x2} t1 An instance of float64x2 to be shuffled. X lane in result + * @param {float64x2} t2 An instance of float64x2 to be shuffled. Y lane in result + * @param {integer} mask One of the 4 shuffle masks, for example, SIMD.XY. + * @return {float64x2} New instance of float64x2 with lanes shuffled. + */ +SIMD.float64x2.shuffleMix = function(t1, t2, mask) { + checkFloat64x2(t1); + checkFloat64x2(t2); + var _x = (mask) & 0x1; + var _y = (mask >> 1) & 0x1; + var storage = _PRIVATE._f64x4; + storage[0] = t1.x_; + storage[1] = t1.y_; + storage[2] = t2.x_; + storage[3] = t2.y_; + return SIMD.float64x2(storage[0 + _x], storage[2 + _y]); +} + +/** + * @param {double} value used for x lane. + * @return {float64x2} New instance of float64x2 with the values in t and + * x replaced with {x}. + */ +SIMD.float64x2.withX = function(t, x) { + checkFloat64x2(t); + return SIMD.float64x2(x, t.y); +} + +/** + * @param {double} value used for y lane. + * @return {float64x2} New instance of float64x2 with the values in t and + * y replaced with {y}. + */ +SIMD.float64x2.withY = function(t, y) { + checkFloat64x2(t); + return SIMD.float64x2(t.x, y); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @param {float64x2} other An instance of float64x2. + * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on + * the result of t < other. + */ +SIMD.float64x2.lessThan = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x < other.x; + var cy = t.y < other.y; + return SIMD.int32x4.bool(cx, cx, cy, cy); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @param {float64x2} other An instance of float64x2. + * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on + * the result of t <= other. + */ +SIMD.float64x2.lessThanOrEqual = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x <= other.x; + var cy = t.y <= other.y; + return SIMD.int32x4.bool(cx, cx, cy, cy); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @param {float64x2} other An instance of float64x2. + * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on + * the result of t == other. + */ +SIMD.float64x2.equal = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x == other.x; + var cy = t.y == other.y; + return SIMD.int32x4.bool(cx, cx, cy, cy); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @param {float64x2} other An instance of float64x2. + * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on + * the result of t != other. + */ +SIMD.float64x2.notEqual = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x != other.x; + var cy = t.y != other.y; + return SIMD.int32x4.bool(cx, cx, cy, cy); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @param {float64x2} other An instance of float64x2. + * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on + * the result of t >= other. + */ +SIMD.float64x2.greaterThanOrEqual = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x >= other.x; + var cy = t.y >= other.y; + return SIMD.int32x4.bool(cx, cx, cy, cy); +} + +/** + * @param {float64x2} t An instance of float64x2. + * @param {float64x2} other An instance of float64x2. + * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on + * the result of t > other. + */ +SIMD.float64x2.greaterThan = function(t, other) { + checkFloat64x2(t); + checkFloat64x2(other); + var cx = t.x > other.x; + var cy = t.y > other.y; + return SIMD.int32x4.bool(cx, cx, cy, cy); +} + +/** + * @param {int32x4} t Selector mask. An instance of int32x4 + * @param {float64x2} trueValue Pick lane from here if corresponding + * selector lanes are 0xFFFFFFFF + * @param {float64x2} falseValue Pick lane from here if corresponding + * selector lanes are 0x0 + * @return {float64x2} Mix of lanes from trueValue or falseValue as + * indicated + */ +SIMD.float64x2.select = function(t, trueValue, falseValue) { + checkInt32x4(t); + checkFloat64x2(trueValue); + checkFloat64x2(falseValue); + var tv = SIMD.int32x4.fromFloat64x2Bits(trueValue); + var fv = SIMD.int32x4.fromFloat64x2Bits(falseValue); + var tr = SIMD.int32x4.and(t, tv); + var fr = SIMD.int32x4.and(SIMD.int32x4.not(t), fv); + return SIMD.float64x2.fromInt32x4Bits(SIMD.int32x4.or(tr, fr)); } /** @@ -450,6 +1018,8 @@ SIMD.float32x4.not = function(a) { * @return {int32x4} New instance of int32x4 with values of a & b. */ SIMD.int32x4.and = function(a, b) { + checkInt32x4(a); + checkInt32x4(b); return SIMD.int32x4(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); } @@ -459,6 +1029,8 @@ SIMD.int32x4.and = function(a, b) { * @return {int32x4} New instance of int32x4 with values of a | b. */ SIMD.int32x4.or = function(a, b) { + checkInt32x4(a); + checkInt32x4(b); return SIMD.int32x4(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); } @@ -468,6 +1040,8 @@ SIMD.int32x4.or = function(a, b) { * @return {int32x4} New instance of int32x4 with values of a ^ b. */ SIMD.int32x4.xor = function(a, b) { + checkInt32x4(a); + checkInt32x4(b); return SIMD.int32x4(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); } @@ -476,6 +1050,7 @@ SIMD.int32x4.xor = function(a, b) { * @return {int32x4} New instance of int32x4 with values of ~t */ SIMD.int32x4.not = function(t) { + checkInt32x4(t); return SIMD.int32x4(~t.x, ~t.y, ~t.z, ~t.w); } @@ -484,6 +1059,7 @@ SIMD.int32x4.not = function(t) { * @return {int32x4} New instance of int32x4 with values of -t */ SIMD.int32x4.neg = function(t) { + checkInt32x4(t); return SIMD.int32x4(-t.x, -t.y, -t.z, -t.w); } @@ -493,6 +1069,8 @@ SIMD.int32x4.neg = function(t) { * @return {int32x4} New instance of int32x4 with values of a + b. */ SIMD.int32x4.add = function(a, b) { + checkInt32x4(a); + checkInt32x4(b); return SIMD.int32x4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } @@ -502,6 +1080,8 @@ SIMD.int32x4.add = function(a, b) { * @return {int32x4} New instance of int32x4 with values of a - b. */ SIMD.int32x4.sub = function(a, b) { + checkInt32x4(a); + checkInt32x4(b); return SIMD.int32x4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } @@ -511,6 +1091,8 @@ SIMD.int32x4.sub = function(a, b) { * @return {int32x4} New instance of int32x4 with values of a * b. */ SIMD.int32x4.mul = function(a, b) { + checkInt32x4(a); + checkInt32x4(b); return SIMD.int32x4(Math.imul(a.x, b.x), Math.imul(a.y, b.y), Math.imul(a.z, b.z), Math.imul(a.w, b.w)); } @@ -521,12 +1103,17 @@ SIMD.int32x4.mul = function(a, b) { * @return {int32x4} New instance of float32x4 with lanes shuffled. */ SIMD.int32x4.shuffle = function(t, mask) { + checkInt32x4(t); var _x = (mask) & 0x3; var _y = (mask >> 2) & 0x3; var _z = (mask >> 4) & 0x3; var _w = (mask >> 6) & 0x3; - return SIMD.int32x4(t.storage_[_x], t.storage_[_y], t.storage_[_z], - t.storage_[_w]); + var storage = _PRIVATE._i32x4; + storage[0] = t.x_; + storage[1] = t.y_; + storage[2] = t.z_; + storage[3] = t.w_; + return SIMD.int32x4(storage[_x], storage[_y], storage[_z], storage[_w]); } /** @@ -536,23 +1123,41 @@ SIMD.int32x4.shuffle = function(t, mask) { * @return {int32x4} New instance of float32x4 with lanes shuffled. */ SIMD.int32x4.shuffleMix = function(t1, t2, mask) { + checkInt32x4(t1); + checkInt32x4(t2); var _x = (mask) & 0x3; var _y = (mask >> 2) & 0x3; var _z = (mask >> 4) & 0x3; var _w = (mask >> 6) & 0x3; - return SIMD.int32x4(t1.storage_[_x], t1.storage_[_y], t2.storage_[_z], - t2.storage_[_w]); -} - -/** - * @param {float32x4} + var storage = _PRIVATE._i32x8; + storage[0] = t1.x_; + storage[1] = t1.y_; + storage[2] = t1.z_; + storage[3] = t1.w_; + storage[4] = t2.x_; + storage[5] = t2.y_; + storage[6] = t2.z_; + storage[7] = t2.w_; + return SIMD.float32x4(storage[0 + _x], storage[0 + _y], + storage[4 + _z], storage[4 + _w]); +} + +/** + * @param {int32x4} t Selector mask. An instance of int32x4 + * @param {int32x4} trueValue Pick lane from here if corresponding + * selector lane is 0xFFFFFFFF + * @param {int32x4} falseValue Pick lane from here if corresponding + * selector lane is 0x0 + * @return {int32x4} Mix of lanes from trueValue or falseValue as + * indicated */ SIMD.int32x4.select = function(t, trueValue, falseValue) { - var tv = SIMD.float32x4.bitsToInt32x4(trueValue); - var fv = SIMD.float32x4.bitsToInt32x4(falseValue); - var tr = SIMD.int32x4.and(t, tv); - var fr = SIMD.int32x4.and(SIMD.int32x4.not(t), fv); - return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(tr, fr)); + checkInt32x4(t); + checkInt32x4(trueValue); + checkInt32x4(falseValue); + var tr = SIMD.int32x4.and(t, trueValue); + var fr = SIMD.int32x4.and(SIMD.int32x4.not(t), falseValue); + return SIMD.int32x4.or(tr, fr); } /** @@ -562,6 +1167,7 @@ SIMD.int32x4.select = function(t, trueValue, falseValue) { * x lane replaced with {x}. */ SIMD.int32x4.withX = function(t, x) { + checkInt32x4(t); return SIMD.int32x4(x, t.y, t.z, t.w); } @@ -572,6 +1178,7 @@ SIMD.int32x4.withX = function(t, x) { * y lane replaced with {y}. */ SIMD.int32x4.withY = function(t, y) { + checkInt32x4(t); return SIMD.int32x4(t.x, y, t.z, t.w); } @@ -582,6 +1189,7 @@ SIMD.int32x4.withY = function(t, y) { * z lane replaced with {z}. */ SIMD.int32x4.withZ = function(t, z) { + checkInt32x4(t); return SIMD.int32x4(t.x, t.y, z, t.w); } @@ -591,6 +1199,7 @@ SIMD.int32x4.withZ = function(t, z) { * w lane replaced with {w}. */ SIMD.int32x4.withW = function(t, w) { + checkInt32x4(t); return SIMD.int32x4(t.x, t.y, t.z, w); } @@ -601,6 +1210,7 @@ SIMD.int32x4.withW = function(t, w) { * x lane replaced with {x}. */ SIMD.int32x4.withFlagX = function(t, flagX) { + checkInt32x4(t); var x = flagX ? 0xFFFFFFFF : 0x0; return SIMD.int32x4(x, t.y, t.z, t.w); } @@ -612,6 +1222,7 @@ SIMD.int32x4.withFlagX = function(t, flagX) { * y lane replaced with {y}. */ SIMD.int32x4.withFlagY = function(t, flagY) { + checkInt32x4(t); var y = flagY ? 0xFFFFFFFF : 0x0; return SIMD.int32x4(t.x, y, t.z, t.w); } @@ -623,6 +1234,7 @@ SIMD.int32x4.withFlagY = function(t, flagY) { * z lane replaced with {z}. */ SIMD.int32x4.withFlagZ = function(t, flagZ) { + checkInt32x4(t); var z = flagZ ? 0xFFFFFFFF : 0x0; return SIMD.int32x4(t.x, t.y, z, t.w); } @@ -634,6 +1246,7 @@ SIMD.int32x4.withFlagZ = function(t, flagZ) { * w lane replaced with {w}. */ SIMD.int32x4.withFlagW = function(t, flagW) { + checkInt32x4(t); var w = flagW ? 0xFFFFFFFF : 0x0; return SIMD.int32x4(t.x, t.y, t.z, w); } @@ -645,6 +1258,8 @@ SIMD.int32x4.withFlagW = function(t, flagW) { * the result of t == other. */ SIMD.int32x4.equal = function(t, other) { + checkInt32x4(t); + checkInt32x4(other); var cx = t.x == other.x; var cy = t.y == other.y; var cz = t.z == other.z; @@ -659,6 +1274,8 @@ SIMD.int32x4.equal = function(t, other) { * the result of t > other. */ SIMD.int32x4.greaterThan = function(t, other) { + checkInt32x4(t); + checkInt32x4(other); var cx = t.x > other.x; var cy = t.y > other.y; var cz = t.z > other.z; @@ -673,6 +1290,8 @@ SIMD.int32x4.greaterThan = function(t, other) { * the result of t < other. */ SIMD.int32x4.lessThan = function(t, other) { + checkInt32x4(t); + checkInt32x4(other); var cx = t.x < other.x; var cy = t.y < other.y; var cz = t.z < other.z; @@ -686,6 +1305,7 @@ SIMD.int32x4.lessThan = function(t, other) { * @return {int32x4} lanes in a shifted by bits. */ SIMD.int32x4.shiftLeft = function(a, bits) { + checkInt32x4(a); var x = a.x << bits; var y = a.y << bits; var z = a.z << bits; @@ -699,6 +1319,7 @@ SIMD.int32x4.shiftLeft = function(a, bits) { * @return {int32x4} lanes in a shifted by bits. */ SIMD.int32x4.shiftRightLogical = function(a, bits) { + checkInt32x4(a); var x = a.x >>> bits; var y = a.y >>> bits; var z = a.z >>> bits; @@ -712,6 +1333,7 @@ SIMD.int32x4.shiftRightLogical = function(a, bits) { * @return {int32x4} lanes in a shifted by bits. */ SIMD.int32x4.shiftRightArithmetic = function(a, bits) { + checkInt32x4(a); var x = a.x >> bits; var y = a.y >> bits; var z = a.z >> bits; @@ -719,31 +1341,6 @@ SIMD.int32x4.shiftRightArithmetic = function(a, bits) { return SIMD.int32x4(x, y, z, w); } -/** - * @param {int32x4} t An instance of int32x4. - * @return {float32x4} a bit-wise copy of t as a float32x4. - */ -SIMD.int32x4.bitsToFloat32x4 = function(t) { - var temp_storage = new Int32Array([t.storage_[0], t.storage_[1], t.storage_[2], t.storage_[3]]); - var alias = new Float32Array(temp_storage.buffer); - var fx4 = SIMD.float32x4.zero(); - fx4.storage_ = alias; - return fx4; -} - -/** - * @param {int32x4} t An instance of int32x4. - * @return {float32x4} with a float to integer conversion copy of t. - */ -SIMD.int32x4.toFloat32x4 = function(t) { - var a = float32x4.zero(); - a.storage_[0] = t.storage_[0]; - a.storage_[1] = t.storage_[1]; - a.storage_[2] = t.storage_[2]; - a.storage_[3] = t.storage_[3]; - return a; -} - Object.defineProperty(SIMD, 'XXXX', { get: function() { return 0x0; } }); Object.defineProperty(SIMD, 'XXXY', { get: function() { return 0x40; } }); Object.defineProperty(SIMD, 'XXXZ', { get: function() { return 0x80; } }); @@ -1001,20 +1598,25 @@ Object.defineProperty(SIMD, 'WWWY', { get: function() { return 0x7F; } }); Object.defineProperty(SIMD, 'WWWZ', { get: function() { return 0xBF; } }); Object.defineProperty(SIMD, 'WWWW', { get: function() { return 0xFF; } }); +Object.defineProperty(SIMD, 'XX', { get: function() { return 0x0; } }); +Object.defineProperty(SIMD, 'XY', { get: function() { return 0x2; } }); +Object.defineProperty(SIMD, 'YX', { get: function() { return 0x1; } }); +Object.defineProperty(SIMD, 'YY', { get: function() { return 0x3; } }); + Object.defineProperty(SIMD.float32x4.prototype, 'x', { - get: function() { return this.storage_[0]; } + get: function() { return this.x_; } }); Object.defineProperty(SIMD.float32x4.prototype, 'y', { - get: function() { return this.storage_[1]; } + get: function() { return this.y_; } }); Object.defineProperty(SIMD.float32x4.prototype, 'z', { - get: function() { return this.storage_[2]; } + get: function() { return this.z_; } }); Object.defineProperty(SIMD.float32x4.prototype, 'w', - { get: function() { return this.storage_[3]; } + { get: function() { return this.w_; } }); /** @@ -1030,36 +1632,55 @@ Object.defineProperty(SIMD.float32x4.prototype, 'signMask', { } }); +Object.defineProperty(SIMD.float64x2.prototype, 'x', { + get: function() { return this.x_; } +}); + +Object.defineProperty(SIMD.float64x2.prototype, 'y', { + get: function() { return this.y_; } +}); + +/** + * Extract the sign bit from each lane return them in the first 2 bits. + */ +Object.defineProperty(SIMD.float64x2.prototype, 'signMask', { + get: function() { + var mx = this.x < 0.0 ? 1 : 0; + var my = this.y < 0.0 ? 1 : 0; + return mx | my << 1; + } +}); + Object.defineProperty(SIMD.int32x4.prototype, 'x', { - get: function() { return this.storage_[0]; } + get: function() { return this.x_; } }); Object.defineProperty(SIMD.int32x4.prototype, 'y', { - get: function() { return this.storage_[1]; } + get: function() { return this.y_; } }); Object.defineProperty(SIMD.int32x4.prototype, 'z', { - get: function() { return this.storage_[2]; } + get: function() { return this.z_; } }); Object.defineProperty(SIMD.int32x4.prototype, 'w', - { get: function() { return this.storage_[3]; } + { get: function() { return this.w_; } }); Object.defineProperty(SIMD.int32x4.prototype, 'flagX', { - get: function() { return this.storage_[0] != 0x0; } + get: function() { return this.x_ != 0x0; } }); Object.defineProperty(SIMD.int32x4.prototype, 'flagY', { - get: function() { return this.storage_[1] != 0x0; } + get: function() { return this.y_ != 0x0; } }); Object.defineProperty(SIMD.int32x4.prototype, 'flagZ', { - get: function() { return this.storage_[2] != 0x0; } + get: function() { return this.z_ != 0x0; } }); Object.defineProperty(SIMD.int32x4.prototype, 'flagW', - { get: function() { return this.storage_[3] != 0x0; } + { get: function() { return this.w_ != 0x0; } }); /** @@ -1067,10 +1688,10 @@ Object.defineProperty(SIMD.int32x4.prototype, 'flagW', */ Object.defineProperty(SIMD.int32x4.prototype, 'signMask', { get: function() { - var mx = (this.storage_[0] & 0x80000000) >>> 31; - var my = (this.storage_[1] & 0x80000000) >>> 31; - var mz = (this.storage_[2] & 0x80000000) >>> 31; - var mw = (this.storage_[3] & 0x80000000) >>> 31; + var mx = (this.x_ & 0x80000000) >>> 31; + var my = (this.y_ & 0x80000000) >>> 31; + var mz = (this.z_ & 0x80000000) >>> 31; + var mw = (this.w_ & 0x80000000) >>> 31; return mx | my << 1 | mz << 2 | mw << 3; } }); From 8367ef671fe83029a93321fab1c86d70f58593dd Mon Sep 17 00:00:00 2001 From: Ningxin Hu Date: Mon, 18 Aug 2014 15:51:43 -0700 Subject: [PATCH 04/60] Update SIMD.js code generation due to API update. --- src/library.js | 36 +++++++++++++-------------- src/parseTools.js | 4 +-- system/include/emscripten/emmintrin.h | 8 +++--- system/include/emscripten/vector.h | 8 +++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/library.js b/src/library.js index 82059d5e9790e..88ef3ee642366 100644 --- a/src/library.js +++ b/src/library.js @@ -8654,7 +8654,7 @@ LibraryManager.library = { //============================ emscripten_float32x4_signmask__inline: function(a) { - return 'SIMD.float32x4.bitsToInt32x4(' + a + ').signMask'; + return a + '.signMask'; }, emscripten_float32x4_min__inline: function(a, b) { @@ -8670,55 +8670,55 @@ LibraryManager.library = { }, emscripten_float32x4_lessThan__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.lessThan(' + a + ', ' + b + '))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.lessThan(' + a + ', ' + b + '))'; }, emscripten_float32x4_lessThanOrEqual__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.lessThanOrEqual(' + a + ', ' + b + '))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.lessThanOrEqual(' + a + ', ' + b + '))'; }, emscripten_float32x4_equal__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.equal(' + a + ', ' + b + '))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.equal(' + a + ', ' + b + '))'; }, emscripten_float32x4_greaterThanOrEqual__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.greaterThanOrEqual(' + a + ', ' + b + '))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.greaterThanOrEqual(' + a + ', ' + b + '))'; }, emscripten_float32x4_greaterThan__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.float32x4.greaterThan(' + a + ', ' + b + '))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.greaterThan(' + a + ', ' + b + '))'; }, emscripten_float32x4_and__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.float32x4.bitsToInt32x4(' + a + '), SIMD.float32x4.bitsToInt32x4(' + b + ')))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.and(' + a + ', ' + b + '))'; }, emscripten_float32x4_andNot__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.int32x4.not(SIMD.float32x4.bitsToInt32x4(' + a + ')), SIMD.float32x4.bitsToInt32x4(' + b + ')))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.and(SIMD.float32x4.not(' + a + '), ' + b + '))'; }, emscripten_float32x4_or__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(SIMD.float32x4.bitsToInt32x4(' + a + '), SIMD.float32x4.bitsToInt32x4(' + b + ')))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.or(' + a + ', ' + b + '))'; }, emscripten_float32x4_xor__inline: function(a, b) { - return 'SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(SIMD.float32x4.bitsToInt32x4(' + a + '), SIMD.float32x4.bitsToInt32x4(' + b + ')))'; + return 'SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.xor(' + a + ', ' + b + '))'; }, - emscripten_int32x4_bitsToFloat32x4__inline: function(a) { - return 'SIMD.int32x4.bitsToFloat32x4(' + a + ')'; + emscripten_float32x4_fromInt32x4Bits__inline: function(a) { + return 'SIMD.float32x4.fromInt32x4Bits(' + a + ')'; }, - emscripten_int32x4_toFloat32x4__inline: function(a) { - return 'SIMD.int32x4.toFloat32x4(' + a + ')'; + emscripten_float32x4_fromInt32x4__inline: function(a) { + return 'SIMD.float32x4.fromInt32x4(' + a + ')'; }, - emscripten_float32x4_bitsToInt32x4__inline: function(a) { - return 'SIMD.float32x4.bitsToInt32x4(' + a + ')'; + emscripten_int32x4_fromFloat32x4Bits__inline: function(a) { + return 'SIMD.int32x4.fromFloat32x4Bits(' + a + ')'; }, - emscripten_float32x4_toInt32x4__inline: function(a) { - return 'SIMD.float32x4.toInt32x4(' + a + ')'; + emscripten_int32x4_fromFloat32x4__inline: function(a) { + return 'SIMD.int32x4.fromFloat32x4(' + a + ')'; }, //============================ diff --git a/src/parseTools.js b/src/parseTools.js index ececf477683cf..c5c4384bda79d 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2387,11 +2387,11 @@ function processMathop(item) { var outType = item.type; if (inType === '<4 x float>') { assert(outType === '<4 x i32>'); - return 'SIMD.float32x4.bitsToInt32x4(' + idents[0] + ')'; + return 'SIMD.int32x4.fromFloat32x4Bits(' + idents[0] + ')'; } else { assert(inType === '<4 x i32>'); assert(outType === '<4 x float>'); - return 'SIMD.int32x4.bitsToFloat32x4(' + idents[0] + ')'; + return 'SIMD.float32x4.fromInt32x4Bits(' + idents[0] + ')'; } } case 'and': return 'SIMD.int32x4.and(' + idents[0] + ',' + idents[1] + ')'; diff --git a/system/include/emscripten/emmintrin.h b/system/include/emscripten/emmintrin.h index 31265db803494..b3278a9b2fbe0 100644 --- a/system/include/emscripten/emmintrin.h +++ b/system/include/emscripten/emmintrin.h @@ -65,23 +65,23 @@ _mm_sub_epi32(__m128i a, __m128i b) static __inline__ __m128 __attribute__((__always_inline__)) _mm_castsi128_ps(__m128i a) { - return emscripten_int32x4_bitsToFloat32x4(a); + return emscripten_float32x4_fromInt32x4Bits(a); } static __inline__ __m128 __attribute__((__always_inline__)) _mm_cvtepi32_ps(__m128i a) { - return emscripten_int32x4_toFloat32x4(a); + return emscripten_float32x4_fromInt32x4(a); } static __inline__ __m128i __attribute__((__always_inline__)) _mm_castps_si128(__m128 a) { - return emscripten_float32x4_bitsToInt32x4(a); + return emscripten_int32x4_fromFloat32x4Bits(a); } static __inline__ __m128i __attribute__((__always_inline__)) _mm_cvtps_epi32(__m128 a) { - return emscripten_float32x4_toInt32x4(a); + return emscripten_int32x4_fromFloat32x4(a); } \ No newline at end of file diff --git a/system/include/emscripten/vector.h b/system/include/emscripten/vector.h index cf26a5d66fca6..39f41764ea290 100644 --- a/system/include/emscripten/vector.h +++ b/system/include/emscripten/vector.h @@ -23,10 +23,10 @@ float32x4 emscripten_float32x4_andNot(float32x4 a, float32x4 b); float32x4 emscripten_float32x4_or(float32x4 a, float32x4 b); float32x4 emscripten_float32x4_xor(float32x4 a, float32x4 b); -float32x4 emscripten_int32x4_bitsToFloat32x4(int32x4 a); -float32x4 emscripten_int32x4_toFloat32x4(int32x4 a); -int32x4 emscripten_float32x4_bitsToInt32x4(float32x4 a); -int32x4 emscripten_float32x4_toInt32x4(float32x4 a); +float32x4 emscripten_float32x4_fromInt32x4Bits(int32x4 a); +float32x4 emscripten_float32x4_fromInt32x4(int32x4 a); +int32x4 emscripten_int32x4_fromFloat32x4Bits(float32x4 a); +int32x4 emscripten_int32x4_fromFloat32x4(float32x4 a); #ifdef __cplusplus } From 3e9d7908048446648510b5942ca9363a8c15574c Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Wed, 20 Aug 2014 11:24:18 +0200 Subject: [PATCH 05/60] add javascript implementation of glutSetCursor function --- src/library_glut.js | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/library_glut.js b/src/library_glut.js index d6293d85ff54e..8ebe79ee511de 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -432,6 +432,64 @@ var LibraryGLUT = { GLUT.mouseFunc = func; }, + glutSetCursor: function(cursor) { + var cursorStyle = 'auto'; + switch(cursor) { + case 0x0002: /* GLUT_CURSOR_INFO */ + cursorStyle = 'pointer'; + break; + case 0x0004: /* GLUT_CURSOR_HELP */ + cursorStyle = 'help'; + break; + case 0x0007: /* GLUT_CURSOR_WAIT */ + cursorStyle = 'wait'; + break; + case 0x0008: /* GLUT_CURSOR_TEXT */ + cursorStyle = 'text'; + break; + case 0x0009: /* GLUT_CURSOR_CROSSHAIR */ + case 0x0066: /* GLUT_CURSOR_FULL_CROSSHAIR */ + cursorStyle = 'crosshair'; + break; + case 0x000A: /* GLUT_CURSOR_UP_DOWN */ + cursorStyle = 'ns-resize'; + break; + case 0x000B: /* GLUT_CURSOR_LEFT_RIGHT */ + cursorStyle = 'ew-resize'; + break; + case 0x000C: /* GLUT_CURSOR_TOP_SIDE */ + cursorStyle = 'n-resize'; + break; + case 0x000D: /* GLUT_CURSOR_BOTTOM_SIDE */ + cursorStyle = 's-resize'; + break; + case 0x000E: /* GLUT_CURSOR_LEFT_SIDE */ + cursorStyle = 'w-resize'; + break; + case 0x000F: /* GLUT_CURSOR_RIGHT_SIDE */ + cursorStyle = 'e-resize'; + break; + case 0x0010: /* GLUT_CURSOR_TOP_LEFT_CORNER */ + cursorStyle = 'nw-resize'; + break; + case 0x0011: /* GLUT_CURSOR_TOP_RIGHT_CORNER */ + cursorStyle = 'ne-resize'; + break; + case 0x0012: /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */ + cursorStyle = 'se-resize'; + break; + case 0x0013: /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ + cursorStyle = 'sw-resize'; + break; + case 0x0065: /* GLUT_CURSOR_NONE */ + cursorStyle = 'none'; + break; + default: + break; + } + Module['canvas'].style.cursor = cursorStyle; + }, + glutCreateWindow__deps: ['$Browser'], glutCreateWindow: function(name) { var contextAttributes = { From 31ef456a4f2ef976e685f16ee2ddcac0ae48af86 Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Wed, 20 Aug 2014 11:36:26 +0200 Subject: [PATCH 06/60] fix indentation --- src/library_glut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_glut.js b/src/library_glut.js index 8ebe79ee511de..1a3bb21c0c31a 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -483,7 +483,7 @@ var LibraryGLUT = { break; case 0x0065: /* GLUT_CURSOR_NONE */ cursorStyle = 'none'; - break; + break; default: break; } From 7075ff4161b4ab4ae62c8cc4c938b84430a5339f Mon Sep 17 00:00:00 2001 From: Antoine Lambert Date: Wed, 20 Aug 2014 15:16:31 +0200 Subject: [PATCH 07/60] handle all possible GLUT cursor value and throw an exception when an invalid one is provided --- src/library_glut.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/library_glut.js b/src/library_glut.js index 1a3bb21c0c31a..d764582d4e5fc 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -435,12 +435,27 @@ var LibraryGLUT = { glutSetCursor: function(cursor) { var cursorStyle = 'auto'; switch(cursor) { + case 0x0000: /* GLUT_CURSOR_RIGHT_ARROW */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0001: /* GLUT_CURSOR_LEFT_ARROW */ + // No equivalent css cursor style, fallback to 'auto' + break; case 0x0002: /* GLUT_CURSOR_INFO */ cursorStyle = 'pointer'; break; + case 0x0003: /* GLUT_CURSOR_DESTROY */ + // No equivalent css cursor style, fallback to 'auto' + break; case 0x0004: /* GLUT_CURSOR_HELP */ cursorStyle = 'help'; break; + case 0x0005: /* GLUT_CURSOR_CYCLE */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0006: /* GLUT_CURSOR_SPRAY */ + // No equivalent css cursor style, fallback to 'auto' + break; case 0x0007: /* GLUT_CURSOR_WAIT */ cursorStyle = 'wait'; break; @@ -481,11 +496,13 @@ var LibraryGLUT = { case 0x0013: /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ cursorStyle = 'sw-resize'; break; + case 0x0064: /* GLUT_CURSOR_INHERIT */ + break; case 0x0065: /* GLUT_CURSOR_NONE */ cursorStyle = 'none'; break; default: - break; + throw "glutSetCursor: Unknown cursor type: " + cursor; } Module['canvas'].style.cursor = cursorStyle; }, From 7b7aeb98405fbf48900925a790c9c4a59b5b568f Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 21 Aug 2014 12:55:42 +1000 Subject: [PATCH 08/60] Addition of Module reference and cross linking to it from elsewhere. Removal from Interacting with code --- .../docs/api_reference/Filesystem-API.rst | 4 +- site/source/docs/api_reference/index.rst | 3 + site/source/docs/api_reference/module.rst | 79 +++++++++++++++++++ .../source/docs/api_reference/preamble.js.rst | 2 +- .../Interacting-with-code.rst | 58 +++++--------- site/source/docs/tools_reference/emcc.rst | 31 ++++---- 6 files changed, 120 insertions(+), 57 deletions(-) create mode 100644 site/source/docs/api_reference/module.rst diff --git a/site/source/docs/api_reference/Filesystem-API.rst b/site/source/docs/api_reference/Filesystem-API.rst index 98e6b8bf5c475..65b04b3025656 100644 --- a/site/source/docs/api_reference/Filesystem-API.rst +++ b/site/source/docs/api_reference/Filesystem-API.rst @@ -1,7 +1,7 @@ .. _Filesystem-API: ===================================== -Filesystem API (under-construction) +File System API (under-construction) ===================================== File I/O in Emscripten is provided by the `FS `_ library. It is used internally for all of Emscripten's **libc** and **libcxx** file I/O. @@ -97,7 +97,7 @@ By default: - ``stdout`` will use a ``print`` function if one such is defined, printing to the terminal in command line engines and to the browser console in browsers that have a console (again, line-buffered). - ``stderr`` will use the same output function as ``stdout``. -.. note:: All the configuration should be done before the main ``run()`` method is executed, typically by implementing ``Module.preRun``, see :ref:`Interacting-with-code`. +.. note:: All the configuration should be done before the main ``run()`` method is executed, typically by implementing :js:attr:`Module.preRun`, see :ref:`Interacting-with-code`. .. js:function:: FS.init(input, output, error) diff --git a/site/source/docs/api_reference/index.rst b/site/source/docs/api_reference/index.rst index d6379d25b09b0..a624cb8af2907 100644 --- a/site/source/docs/api_reference/index.rst +++ b/site/source/docs/api_reference/index.rst @@ -18,6 +18,8 @@ This section lists Emscripten's public API, organised by header file. At very hi - **Filesystem-API (library_fs.js)**: *APIs for (primarily) synchronous File I/O.* +- **Module**: **User-populated global JavaScript object, with attributes that Emscripten-generated code calls at various points in its execution.** + - **val.h**: *Embind APIs for* **HamishW** - add description - **bind.h**: *Embind APIs for* **HamishW** - add description @@ -34,6 +36,7 @@ This section lists Emscripten's public API, organised by header file. At very hi html5.h preamble.js Filesystem-API + module val.h bind.h advanced-apis diff --git a/site/source/docs/api_reference/module.rst b/site/source/docs/api_reference/module.rst new file mode 100644 index 0000000000000..a618968d39786 --- /dev/null +++ b/site/source/docs/api_reference/module.rst @@ -0,0 +1,79 @@ +.. _module: + +==================================== +Module object (ready-for-review) +==================================== + +``Module`` is a global JavaScript object, with attributes that Emscripten-generated code calls at various points in its execution. + +Developers provide an implementation of ``Module`` to control the execution of code. For example, to define how notification messages from Emscripten are displayed, developers implement the :js:attr:`Module.print` attribute. + +.. note:: ``Module`` is also used to provide access functions (see :js:func:`ccall`) in a way that avoids issues with function name minification at higher optimisation levels. These functions are documented as part of their own APIs. + +.. contents:: Table of Contents + :local: + :depth: 1 + + +.. _module-creating: + +Creating Module +================ + +Use :ref:`emcc's ` ``--pre-js`` option to add JavaScript code that defines (or extends) the ``Module`` object with the behaviour you need. + +When generating only JavaScript, no ``Module`` object is created by default, and the behaviour is entirely defined by the developer. For example, creating a ``Module`` object with the following code will cause all notifications from the program to be calls to ``alert()``. + + :: + + var Module = { + 'print': function(text) { alert(text) } + }; + +.. important:: If you run closure compiler on your code (which is done by default in optimisation level :ref:`-02 ` and higher), you will need quotation marks around the properties of ``Module`` as in the example above (and you need to run closure on the compiled code together with the declaration of ``Module``). + +When generating HTML, Emscripten creates a ``Module`` object with default methods (see `src/shell.html `_). In this case you should again use ``--pre-js``, but this time to add properties to the existing ``Module`` object. + + + +Affecting execution +=================== + +The following ``Module`` attributes affect code execution. + + +.. js:attribute:: Module.print + + Called when something is printed to standard output. + + + +.. js:attribute:: Module.arguments + + The commandline arguments. The value of ``arguments`` is what is returned if compiled code checks ``argc`` and ``argv``. + + +.. js:attribute:: Module.preInit + + A function (or array of functions) that must be called before global initializers run, but after basic initialization of the JavaScript runtime. This is typically used for :ref:`File System operations ` and is called befroe C++ initializers have been run. + + +.. js:attribute:: Module.preRun + + A function (or array of functions) to call right before calling ``run()``, but after defining and setting up the environment, including global initializers. This is useful, for example, to set up directories and files using the :ref:`Filesystem-API` (since that needs the FileSystem API to be defined, but also needs to be done before the program starts to run. + + .. note:: If code needs to affect global initializers, it should instead be run using :js:attr:`preInit`. + + +.. js:attribute:: Module.noInitialRun + + If set to ``true``, ``main()`` will not be automatically called (you can do so yourself later). The program will still call global initializers, set up memory initialization, and so forth. + + +.. js:attribute:: Module.noExitRuntime + + If set to ``true``, the runtime is not shut down after ``run`` completes. Shutting down the runtime calls shutdown callbacks, for example ``atexit`` calls. If you want to be able to continue to use the code after ``run()`` finishes, it is safer to set this. + + + + diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index 02e3e5eeadb6c..1da8db591d808 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -4,7 +4,7 @@ preamble.js The JavaScript APIs in `preamble.js `_ provide programmatic access for interacting with the compiled C code, including: calling compiled C functions, accessing memory, converting pointers to JavaScript ``Strings`` and ``Strings`` to pointers (with different encodings/formats), and other convenience functions. -.. note:: All functions should be called though the ``Module`` object (for example: ``Module.functionName``). At optimisation ``-O2`` (and higher) function names are minified by the closure compiler, and calling them directly will fail. +.. note:: All functions should be called though the :ref:`Module ` object (for example: ``Module.functionName``). At optimisation ``-O2`` (and higher) function names are minified by the closure compiler, and calling them directly will fail. .. contents:: Table of Contents diff --git a/site/source/docs/coding/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/coding/connecting_cpp_and_javascript/Interacting-with-code.rst index a20fccb4d31dc..8136b4dd9fb17 100644 --- a/site/source/docs/coding/connecting_cpp_and_javascript/Interacting-with-code.rst +++ b/site/source/docs/coding/connecting_cpp_and_javascript/Interacting-with-code.rst @@ -6,16 +6,13 @@ Interacting with code (wiki-import) .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Interacting with Compiled Code -============================== - (If you are looking for how compiled code interacts with the browser environment, see :ref:`Emscripten-Browser-Environment`.) There are various ways to connect and interact between JS and compiled C++ in JS. An overview appears in the second half of these slides: http://kripken.github.io/mloc\_emscripten\_talk/qcon.html Calling Compiled Functions From Normal JavaScript -------------------------------------------------- +================================================= It's easy to call compiled code from normal JavaScript. For example, run this command in the Emscripten home directory: @@ -46,7 +43,7 @@ Some things to keep in mind with :js:func:`ccall` and :js:func:`cwrap`: **Note:** you need ``_`` at the beginning of the functions when exporting (but not with ccall), and note also that you need to use ``Module.ccall`` and not :js:func:`ccall` by itself, since closure will minify the function name, leaving only the Module object where we export names. Accessing Memory ----------------- +================ You can access memory using :js:func:`getValue(ptr, type) ` and :js:func:`setValue(ptr, value, type) `. The first argument is a pointer, a number representing a memory address. ``type`` must be an LLVM IR type, one of ``i8,i16,i32,i64,float,double`` or a pointer type like ``i8*`` (or just ``*``). Note that the types here are not as in :js:func:`ccall` and :js:func:`cwrap` - this is a lower-level operation, and we do need to care what specific integer etc. type is being used. @@ -62,7 +59,7 @@ You can also access memory 'directly' by manipulating the arrays that represent That allocates a buffer, copies in some data, then calls a C function to process the data, and finally frees the buffer. Here ``my_function`` is a C function that receives a single integer parameter (could be a pointer as well, as they are just 32-bit integers for us), and returns an integer as well, something like ``int my_function(char *buf)``. Calling JavaScript From C/C++ ------------------------------ +============================= The most direct way is to just use :c:func:`emscripten_run_script`, which basically runs some JS code from C/C++ using eval. So ``emscripten_run_script("alert('hi')");`` will show an alert with 'hi' (note: this calls ``alert`` which is present in browsers, but not in node or other JS shells. You can call ``Module.print`` to print to stdout). This is not very fast though. A faster alternative is to write "inline JavaScript", basically the same as inline assembly would be used, for example @@ -127,22 +124,22 @@ You can use the emcc option ``--js-library`` to add a file with such code, inste - JS libraries can declare dependencies (``__deps``, see examples in ``library*.js``), however those are only for other JS libraries. If a JS library depends on a compiled C library (like most of libc), you must edit ``src/deps_info.json``, see ``tools/system_libs.py`` (search for deps\_info). Calling JS functions as function pointers from C -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------------------------- You can use ``Runtime.addFunction`` to return an integer value that represents a function pointer. Passing that integer to C code then lets it call that value as a function pointer, and the JS function you sent to ``Runtime.addFunction`` will be called. See ``test_add_function`` in ``tests/test_core.py`` for an example. WebIDL Binder -------------- +============= The :ref:`WebIDL-Binder` is a tool to make C++ classes usable from JS as JS classes. It is used to port Bullet Physics to the web in the **ammo.js** project, and is a fairly simple lightweight approach to binding between the two languages. Embind ------- +====== Embind is a method to communicate from JS to C++ and C++ to JS, in a C++-like manner (whereas JS libraries are using C APIs, and just one direction). The only downside is that it is not as lightweight as JS libraries or the WebIDL binder. Docs: :ref:`embind`. -Other Methods -------------- +Other methods +============= You can directly interact in various other ways with the compiled code: @@ -152,44 +149,25 @@ You can directly interact in various other ways with the compiled code: - There are various other convenience functions, see **preamble.js** (that file will be included with the generated code). - For filesystem-related manners, see the :ref:`Filesystem-Guide`. -Affecting Execution -------------------- - -You can affect how code runs by creating an object called ``Module`` before the compiled script. Certain properties on ``Module`` can then have various effects: - -- ``arguments``: The commandline arguments (if the compiled code checks ``argc``, ``argv``, it will be seeing ``arguments``) -- ``print``: Called when something is printed to standard output. -- ``preInit``: A function (or array of functions) to call before global initializers run, but after basic initialization of the JS runtime (so you can do ``FS.*`` stuff, but no C++ initializers were called yet). -- ``preRun``: A function (or array of functions) to call right before calling ``run``, but after defining and setting up the environment, including global initializers. This is useful, for example, to set up directories and files using the FileSystem API (since that needs the FileSystem API to be defined, but also needs to be done before the program starts to run; if you need to affect global initializers, though, you should use preInit). -- ``noInitialRun``: If set to true, ``main()`` will not be called. The program will still call global initializers, set up memory initialization, and so forth. You can then call ``main()`` yourself later. -- ``noExitRuntime``: If set to true, the runtime is not shut down after ``run`` is called. Shutting down the runtime calls shutdown callbacks, for example ``atexit`` calls. If you want to be able to continue to use the code after ``run`` finishes, it is safer to set this. - -For example, - -:: - - var Module = { - 'print': function(text) { alert(text) } - }; +Affecting execution +=================== -This will cause all printouts from the program to be calls to ``alert``. +``Module`` is a global JavaScript object, with attributes that Emscripten-generated code calls at various points in its execution. -**Important**: If you run closure compiler on your code (which is done by default in ``-O2`` and above), you will need quotation marks around the properties of ``Module`` as in the example above (and you need to run closure on the compiled code together with the declaration of ``Module``). +Developers provide an implementation of ``Module`` to control, for example, how notifications from Emscripten are displayed, which files that are loaded before the main loop is run, etc. For more information see :ref:`module`. -Setting Module -~~~~~~~~~~~~~~ -When generating just JavaScript, no Module object is created. So you can use emcc's ``--pre-js`` to add some JS code that defines the Module object with the stuff you need. +Environment variables +============================== -When generating HTML, a Module object is created for you and filled with some defaults for printing, etc. (compile a little hello world example to see, or view ``src/shell.html``). The simplest thing is to use ``--pre-js`` to add some JS code that adds properties to that existing Module object. +Sometimes compiled code needs to access environment variables (for instance, in C, by calling the ``getenv()`` function). Just as with the file system, Emscripten generated JavaScript cannot access the computer's environment variables directly, so a virtualised environment is provided. -Environment variables -~~~~~~~~~~~~~~~~~~~~~ +The JavaScript object ``ENV`` contains these virtualised environment variables, and by modifying it you can pass variables to your compiled code. Care must be taken to ensure that the ``ENV`` variable has been initialised by Emscripten before it is modified - using :js:attr:`Module.preRun` is a convenient way to do this. -Sometimes, the code you are compiling will want to access environment variables (for instance, in C, by calling the ``getenv()`` function). Just as with the filesystem, emscripten generated JavaScript cannot access the computer's environment variables so a virtualised environment is provided. The JavaScript object ``ENV`` contains these virtualised environment variables, and by modifying it you can pass variables to your compiled code. Care must be taken to ensure that the ``ENV`` variable has been initialised by Emscripten before it is modified - using ``Module.preRun`` is a convenient way to do this. For example to set an environment variable ``MY_FILE_ROOT`` to be ``"/usr/lib/test/"`` you could add +For example to set an environment variable ``MY_FILE_ROOT`` to be ``"/usr/lib/test/"`` you could add the following JavaScript to your :ref:`setup code `: .. code:: javascript Module.preRun.push(function() {ENV.MY_FILE_ROOT = "/usr/lib/test"}) -to your setup code, as described above. + diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index b7e4abc022cf7..585910c85f002 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -1,13 +1,11 @@ .. _emccdoc: -========================================================= -Emscripten Compiler Frontend (emcc) (under-construction) -========================================================= +====================================================== +Emscripten Compiler Frontend (emcc) (ready-for-review) +====================================================== **This document provides the command syntax for the Emscription Compiler Frontend.** -.. comment - The information in this page was output by running ``emcc --help`` on the version of *emcc* in the Emscripten 1.20.0 SDK. The most recent version is `emcc (master) `_ - Purpose ============================================ @@ -23,10 +21,6 @@ Command line syntax The input file(s) can be either source code files that *Clang* can handle (C or C++), LLVM bitcode in binary form, or LLVM assembly files in human-readable form. -Supported targets include: llvm bitcode, JavaScript, NOT elf (autoconf likes to see elf above to enable shared object support). - -.. todo:: **HamishW** The line above makes no sense. Checking with Alon. - Arguments --------- @@ -49,6 +43,7 @@ Options that are modified or new in *emcc* are listed below: ``-O0`` No optimizations (default). This is the recommended setting for starting to port a project, as it includes various assertions. +.. _emcc-O1: ``-O1`` Simple optimizations. These include using **asm.js**, LLVM ``-O1`` optimizations, relooping, removing runtime assertions and C++ exception catching, and enabling ``-s ALIASING_FUNCTION_POINTERS=1``. This is the recommended setting when you want a reasonably optimized build that is generated as quickly as possible (it builds much faster than ``-O2``). @@ -57,6 +52,8 @@ Options that are modified or new in *emcc* are listed below: - For details on the affects of different opt levels, see ``apply_opt_level()`` in `tools/shared.py `_ and also `src/settings.js `_. - To re-enable C++ exception catching, use ``-s DISABLE_EXCEPTION_CATCHING=0``. + +.. _emcc-O2: ``-O2`` Like ``-O1``, but with various JavaScript-level optimizations and LLVM ``-O3`` optimizations. @@ -69,6 +66,8 @@ Options that are modified or new in *emcc* are listed below: ``-Oz`` Like ``-Os``, but reduces code size even further. +.. _emcc-O3: + ``-O3`` Like ``-O2``, but with additional JavaScript optimizations that can take a significant amount of compilation time and/or are relatively new. @@ -167,7 +166,9 @@ Options that are modified or new in *emcc* are listed below: - If closure compiler hits an out-of-memory, try adjusting ``JAVA_HEAP_SIZE`` in the environment (for example, to 4096m for 4GB). - Closure is only run if JavaScript opts are being done (``-O2`` or above, or ``--js-opts 1``). - + +.. _emcc-pre-js: + ``--pre-js `` Specify a file whose contents are added before the generated code. This is done *before* optimization, so it will be minified properly if the *Closure Compiler* is run. @@ -197,7 +198,7 @@ Options that are modified or new in *emcc* are listed below: For more information about the ``--preload-file`` options, see :ref:`Filesystem-Guide`. ``--exclude-file `` - Files and directories to be excluded from :ref:`--embed-file ` and :ref:`--preload-file `. Wildcard is supported. + Files and directories to be excluded from :ref:`--embed-file ` and :ref:`--preload-file `. Wildcards (*) are supported. ``--shell-file `` The path name to a skeleton HTML file used when generating HTML output. The shell file used needs to have this token inside it: ``{{{ SCRIPT }}}``. @@ -276,8 +277,8 @@ Options that are modified or new in *emcc* are listed below: - ``0``: Do not emit a separate memory initialization file (default). Instead keep the static initialization inside the generated JavaScript as text. - ``1``: Emit a separate memory initialization file in binary format. This is more efficient than storing it as text inside JavaScript, but does mean you have another file to publish. The binary file will also be loaded asynchronously, which means ``main()`` will not be called until the file is downloaded and applied; you cannot call any C functions until it arrives. - .. note:: Call yourself from ``main()`` to know when all asynchronous processing has completed and it is safe to call library functions, as ``main()`` will only be called at that time. You can also call ``addOnPreMain`` from a ``preRun``. - + .. note:: The :ref:`safest way ` to ensure that it is safe to call C functions (the initialisation file has loaded) is to call a notifier function from ``main()``. You might also call ``addOnPreMain`` from a :js:attr:`Module.preRun`. + ``-Wno-warn-absolute-paths`` Suppress warnings about the use of absolute paths in ``-I`` and ``-L`` command line directives. This is used to hide the warnings and acknowledge that the explicit use of absolute paths is intentional. @@ -315,7 +316,9 @@ Options that are modified or new in *emcc* are listed below: .. note:: If ``--memory-init-file`` is used, then in addition to the **.js** or **.html** file which is generated, a **.mem** file will also be created. ``-c`` - Tells *gcc* not to run the linker and causes LLVM bitcode to be generated, as *emcc* only generates JavaScript in the final linking stage of building. + Tells *gcc* to generate LLVM bitcode (only). The linker is not run, and the final JavaScript executable is not produced. + + Environment variables ===================== From 4df83e7f812fa7836db11d4c8c5b18fcad7c9a36 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Thu, 21 Aug 2014 13:02:30 +0300 Subject: [PATCH 09/60] Adjust clang version check to detect custom compiler vendor strings. #2698 --- tools/shared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index f9394be51a0c8..3bb1db301b364 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -273,7 +273,8 @@ def new(*args): def get_clang_version(): global actual_clang_version if actual_clang_version is None: - actual_clang_version = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0].split(' ')[2] + ver = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0].split(' ') + actual_clang_version = ver[ver.index('version')+1] return actual_clang_version def check_clang_version(): From 424b709cac07c3735007b2c31c24caed5dcedc24 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Aug 2014 14:46:58 -0700 Subject: [PATCH 10/60] move alignment and type utilities out of Runtime, as not needed at runtime --- src/analyzer.js | 14 ++++++------- src/compiler.js | 4 +++- src/intertyper.js | 6 +++--- src/jsifier.js | 6 +++--- src/modules.js | 2 +- src/parseTools.js | 48 ++++++++++++++++++++++----------------------- src/runtime.js | 50 ++++++++++++++++++++++++----------------------- 7 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/analyzer.js b/src/analyzer.js index 73691937ef504..4380a76588a74 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -189,7 +189,7 @@ function analyzer(data, sidePass) { if (USE_TYPED_ARRAYS == 2) { function getLegalVars(base, bits, allowLegal) { bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits - if (allowLegal && bits <= 32) return [{ intertype: 'value', ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits, type: 'i' + bits }]; + if (allowLegal && bits <= 32) return [{ intertype: 'value', ident: base + ('i' + bits in Compiletime.INT_TYPES ? '' : '$0'), bits: bits, type: 'i' + bits }]; if (isNumber(base)) return getLegalLiterals(base, bits); if (base[0] == '{') { warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit'); @@ -641,8 +641,8 @@ function analyzer(data, sidePass) { case 'bitcast': { var inType = item.type2; var outType = item.type; - if ((inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) || - (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) { + if ((inType in Compiletime.INT_TYPES && outType in Compiletime.FLOAT_TYPES) || + (inType in Compiletime.FLOAT_TYPES && outType in Compiletime.INT_TYPES)) { i++; continue; // special case, handled in processMathop } @@ -948,7 +948,7 @@ function analyzer(data, sidePass) { if (type.length == 1) return; if (Types.types[type]) return; if (['internal', 'hidden', 'inbounds', 'void'].indexOf(type) != -1) return; - if (Runtime.isNumberType(type)) return; + if (Compiletime.isNumberType(type)) return; dprint('types', 'Adding type: ' + type); // 'blocks': [14 x %struct.X] etc. If this is a pointer, we need @@ -1264,7 +1264,7 @@ function analyzer(data, sidePass) { variable.impl = VAR_NATIVE; } else if (MICRO_OPTS && variable.origin === 'alloca' && !variable.hasValueTaken && variable.allocatedNum === 1 && - (Runtime.isNumberType(pointedType) || Runtime.isPointerType(pointedType))) { + (Compiletime.isNumberType(pointedType) || isPointerType(pointedType))) { // A pointer to a value which is only accessible through this pointer. Basically // a local value on the stack, which nothing fancy is done on. So we can // optimize away the pointing altogether, and just have a native variable @@ -1311,7 +1311,7 @@ function analyzer(data, sidePass) { func.lines.forEach(function(line, i) { if (line.intertype === 'load') { // Floats have no concept of signedness. Mark them as 'signed', which is the default, for which we do nothing - if (line.type in Runtime.FLOAT_TYPES) { + if (line.type in Compiletime.FLOAT_TYPES) { line.unsigned = false; return; } @@ -1681,7 +1681,7 @@ function analyzer(data, sidePass) { hasAlloca = true; if (USE_TYPED_ARRAYS === 2) { // We need to keep the stack aligned - item.allocatedSize = Runtime.forceAlign(item.allocatedSize, Runtime.STACK_ALIGN); + item.allocatedSize = RuntimeGenerator.forceAlign(item.allocatedSize, Runtime.STACK_ALIGN); } } var index = 0; diff --git a/src/compiler.js b/src/compiler.js index 2a98b129f44f2..3a0886fe39647 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -308,7 +308,7 @@ function compile(raw) { B = new Benchmarker(); -try { +//try { if (ll_file) { if (phase === 'glue') { compile(';'); @@ -318,6 +318,7 @@ try { compile(ll_file); // we are given raw .ll } } +/* } catch(err) { if (err.indexOf('Aborting compilation due to previous errors') != -1) { // Compiler failed on user error, print out the error message. @@ -343,6 +344,7 @@ try { }, 500); } else throw err; } +*/ //var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] }); //printErr(dump(M.slice(M.length-10))); diff --git a/src/intertyper.js b/src/intertyper.js index 323787acd3009..244eec696cc0d 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -417,7 +417,7 @@ function intertyper(lines, sidePass, baseLineNums) { } Types.needAnalysis[type] = 0; - if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) { + if (Compiletime.isNumberType(type) || pointingLevels(type) >= 1) { return { value: toNiceIdent(value.text), type: type }; } else if (value.text in ZEROINIT_UNDEF) { // undef doesn't really need initting, but why not return { intertype: 'emptystruct', type: type }; @@ -464,7 +464,7 @@ function intertyper(lines, sidePass, baseLineNums) { if (item.tokens[0].text == 'type') { var fields = []; var packed = false; - if (Runtime.isNumberType(item.tokens[1].text)) { + if (Compiletime.isNumberType(item.tokens[1].text)) { // Clang sometimes has |= i32| instead of |= { i32 }| fields = [item.tokens[1].text]; } else if (item.tokens[1].text != 'opaque') { @@ -821,7 +821,7 @@ function intertyper(lines, sidePass, baseLineNums) { function allocaHandler(item) { item.intertype = 'alloca'; item.allocatedType = item.tokens[1].text; - if (item.tokens.length > 3 && Runtime.isNumberType(item.tokens[3].text)) { + if (item.tokens.length > 3 && Compiletime.isNumberType(item.tokens[3].text)) { item.ident = toNiceIdent(item.tokens[4].text); } else { item.ident = 1; diff --git a/src/jsifier.js b/src/jsifier.js index 0842d32cbee15..d9d9fd39e2040 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -207,7 +207,7 @@ function JSify(data, functionsOnly) { //dprint('jsifier const: ' + JSON.stringify(value) + ',' + type + '\n'); if (value.intertype in PARSABLE_LLVM_FUNCTIONS) { return [finalizeLLVMFunctionCall(value)]; - } else if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) { + } else if (Compiletime.isNumberType(type) || pointingLevels(type) >= 1) { return [makeGlobalUse(indexizeFunctions(parseNumerical(value.value), type))]; } else if (value.intertype === 'emptystruct') { return makeEmptyStruct(type); @@ -282,7 +282,7 @@ function JSify(data, functionsOnly) { if (item.external) { if (LibraryManager.library[item.ident.slice(1)]) { constant = LibraryManager.library[item.ident.slice(1)]; - } else if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { + } else if (Compiletime.isNumberType(item.type) || isPointerType(item.type)) { constant = zeros(Runtime.getNativeFieldSize(item.type)); } else { constant = makeEmptyStruct(item.type); @@ -1550,7 +1550,7 @@ function JSify(data, functionsOnly) { } else { var size = calcAllocatedSize(removeAllPointing(type)); ret = makeCopyValues(getFastValue('tempVarArgs', '+', offset), arg, size, null, null, varargsByVals[i], ','); - offset += Runtime.forceAlign(size, Runtime.STACK_ALIGN); + offset += RuntimeGenerator.forceAlign(size, Runtime.STACK_ALIGN); } return ret; }).filter(function(arg) { diff --git a/src/modules.js b/src/modules.js index 8adba58b5e443..fd7b212417b4c 100644 --- a/src/modules.js +++ b/src/modules.js @@ -279,7 +279,7 @@ var Functions = { for (var i = 0; i < argTypes.length; i++) { var type = argTypes[i]; if (!type) break; // varargs - if (type in Runtime.FLOAT_TYPES) { + if (type in Compiletime.FLOAT_TYPES) { sig += Functions.getSignatureLetter(type); } else { var chunks = getNumIntChunks(type); diff --git a/src/parseTools.js b/src/parseTools.js index c5c4384bda79d..cb912ece1d21a 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -148,7 +148,7 @@ function isStructPointerType(type) { // we must check later on, in call(), where we have more // context, to differentiate such cases. // A similar thing happens in isStructType() - return !Runtime.isNumberType(type) && type[0] == '%'; + return !Compiletime.isNumberType(type) && type[0] == '%'; } function isPointerType(type) { @@ -222,7 +222,7 @@ function getNumIntChunks(type) { } function isIdenticallyImplemented(type1, type2) { - var floats = +(type1 in Runtime.FLOAT_TYPES) + +(type2 in Runtime.FLOAT_TYPES); + var floats = +(type1 in Compiletime.FLOAT_TYPES) + +(type2 in Compiletime.FLOAT_TYPES); if (floats == 2) return true; if (floats == 1) return false; return getNumIntChunks(type1) == getNumIntChunks(type2); @@ -326,7 +326,7 @@ function getReturnType(type) { var isTypeCache = {}; // quite hot, optimize as much as possible function isType(type) { if (type in isTypeCache) return isTypeCache[type]; - var ret = isPointerType(type) || isVoidType(type) || Runtime.isNumberType(type) || isStructType(type) || isFunctionType(type); + var ret = isPointerType(type) || isVoidType(type) || Compiletime.isNumberType(type) || isStructType(type) || isFunctionType(type); isTypeCache[type] = ret; return ret; } @@ -338,7 +338,7 @@ function isVarArgsFunctionType(type) { } function getNumLegalizedVars(type) { // how many legalized variables are needed to represent this type - if (type in Runtime.FLOAT_TYPES) return 1; + if (type in Compiletime.FLOAT_TYPES) return 1; return Math.max(getNumIntChunks(type), 1); } @@ -1032,7 +1032,7 @@ function calcAllocatedSize(type) { // i32, 0, 0, 0 - for example, an int32 is here, then nothing to do for the 3 next bytes, naturally function generateStructTypes(type) { if (isArray(type)) return type; // already in the form of [type, type,...] - if (Runtime.isNumberType(type) || isPointerType(type)) { + if (Compiletime.isNumberType(type) || isPointerType(type)) { if (USE_TYPED_ARRAYS == 2 && type == 'i64') { return ['i64', 0, 0, 0, 'i32', 0, 0, 0]; } @@ -1051,7 +1051,7 @@ function generateStructTypes(type) { for (var i = 0; i < num; i++) { var type = array ? typeData.fields[0] : typeData.fields[i]; if (!SAFE_HEAP && isPointerType(type)) type = '*'; // do not include unneeded type names without safe heap - if (Runtime.isNumberType(type) || isPointerType(type)) { + if (Compiletime.isNumberType(type) || isPointerType(type)) { if (USE_TYPED_ARRAYS == 2 && type == 'i64') { ret[index++] = 'i64'; ret[index++] = 0; @@ -1065,7 +1065,7 @@ function generateStructTypes(type) { } ret[index++] = type; } else { - if (Runtime.isStructType(type) && type[1] === '0') { + if (isStructType(type) && type[1] === '0') { // this is [0 x something], which does nothing // XXX this happens in java_nbody... assert(i === typeData.fields.length-1); continue; @@ -1200,7 +1200,7 @@ function asmEnsureFloat(value, type) { // ensures that a float type has either 5 value = ensureDot(value); return 'Math_fround(' + value + ')'; } - if (type in Runtime.FLOAT_TYPES) { + if (type in Compiletime.FLOAT_TYPES) { return ensureDot(value); } else { return value; @@ -1208,7 +1208,7 @@ function asmEnsureFloat(value, type) { // ensures that a float type has either 5 } function asmInitializer(type) { - if (type in Runtime.FLOAT_TYPES) { + if (type in Compiletime.FLOAT_TYPES) { if (PRECISE_F32 && type === 'float') return 'Math_fround(0)'; return RUNNING_JS_OPTS ? '+0' : '.0'; } else { @@ -1220,7 +1220,7 @@ function asmCoercion(value, type, signedness) { if (!ASM_JS) return value; if (type == 'void') { return value; - } else if (type in Runtime.FLOAT_TYPES) { + } else if (type in Compiletime.FLOAT_TYPES) { if (isNumber(value)) { return asmEnsureFloat(value, type); } else { @@ -1327,7 +1327,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); if (ASM_JS) { - if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); + if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); // else fall through } else { return asmCoercion('SAFE_HEAP_LOAD(' + offset + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); @@ -1338,8 +1338,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa ret = asmCoercion(ret, type); } if (ASM_HEAP_LOG) { - ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, - 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int')); + ret = makeInlineCalculation('(asmPrint' + (type in Compiletime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, + 'temp' + (type in Compiletime.FLOAT_TYPES ? 'Double' : 'Int')); } return ret; } @@ -1439,7 +1439,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); if (ASM_JS) { - if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ')', type); + if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ')', type); // else fall through } else { return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; @@ -1610,7 +1610,7 @@ function getFastValue(a, op, b, type) { if (op === '*') { // We can't eliminate where a or b are 0 as that would break things for creating // a negative 0. - if ((aNumber === 0 || bNumber === 0) && !(type in Runtime.FLOAT_TYPES)) { + if ((aNumber === 0 || bNumber === 0) && !(type in Compiletime.FLOAT_TYPES)) { return '0'; } else if (aNumber === 1) { return b; @@ -1622,7 +1622,7 @@ function getFastValue(a, op, b, type) { return '(' + a + '<<' + shifts + ')'; } } - if (!(type in Runtime.FLOAT_TYPES)) { + if (!(type in Compiletime.FLOAT_TYPES)) { // if guaranteed small enough to not overflow into a double, do a normal multiply var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there @@ -1632,7 +1632,7 @@ function getFastValue(a, op, b, type) { return '(Math_imul(' + a + ',' + b + ')|0)'; } } else if (op === '/') { - if (a === '0' && !(type in Runtime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0 + if (a === '0' && !(type in Compiletime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0 return '0'; } else if (b === 1) { return a; @@ -1801,9 +1801,9 @@ function makeGetSlabs(ptr, type, allowMultiple, unsigned) { if (!USE_TYPED_ARRAYS) { return ['HEAP']; } else if (USE_TYPED_ARRAYS == 1) { - if (type in Runtime.FLOAT_TYPES || type === 'int64') { // XXX should be i64, no? + if (type in Compiletime.FLOAT_TYPES || type === 'int64') { // XXX should be i64, no? return ['FHEAP']; // If USE_FHEAP is false, will fail at runtime. At compiletime we do need it for library stuff. - } else if (type in Runtime.INT_TYPES || isPointerType(type)) { + } else if (type in Compiletime.INT_TYPES || isPointerType(type)) { return [unsigned ? 'IHEAPU' : 'IHEAP']; } else { assert(allowMultiple, 'Unknown slab type and !allowMultiple: ' + type); @@ -2351,13 +2351,13 @@ function processMathop(item) { assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2'); var inType = item.params[0].type; var outType = item.type; - if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) { + if (inType in Compiletime.INT_TYPES && outType in Compiletime.FLOAT_TYPES) { if (legalizedI64s) { return '(' + makeSetTempDouble(0, 'i32', idents[0] + '$0') + ', ' + makeSetTempDouble(1, 'i32', idents[0] + '$1') + ', ' + makeGetTempDouble(0, 'double') + ')'; } else { return makeInlineCalculation(makeSetTempDouble(0, 'i32', 'VALUE[0]') + ',' + makeSetTempDouble(1, 'i32', 'VALUE[1]') + ',' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64'); } - } else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) { + } else if (inType in Compiletime.FLOAT_TYPES && outType in Compiletime.INT_TYPES) { if (legalizedI64s) { return makeSetTempDouble(0, 'double', idents[0]) + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]); } else { @@ -2537,10 +2537,10 @@ function processMathop(item) { // Most bitcasts are no-ops for us. However, the exception is int to float and float to int var inType = item.params[0].type; var outType = item.type; - if ((inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) || - (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) { + if ((inType in Compiletime.INT_TYPES && outType in Compiletime.FLOAT_TYPES) || + (inType in Compiletime.FLOAT_TYPES && outType in Compiletime.INT_TYPES)) { assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2'); - if (inType in Runtime.INT_TYPES) { + if (inType in Compiletime.INT_TYPES) { return '(' + makeSetTempDouble(0, 'i32', idents[0]) + ',' + makeGetTempDouble(0, 'float') + ')'; } else { return '(' + makeSetTempDouble(0, 'float', idents[0]) + ',' + makeGetTempDouble(0, 'i32') + ')'; diff --git a/src/runtime.js b/src/runtime.js index 44c36668dea7c..b86ba0bcfa8ab 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -71,11 +71,22 @@ var RuntimeGenerator = { return ret; }, + forceAlign: function(target, quantum) { + quantum = quantum || {{{ QUANTUM_SIZE }}}; + if (quantum == 1) return target; + if (isNumber(target) && isNumber(quantum)) { + return Math.ceil(target/quantum)*quantum; + } else if (isNumber(quantum) && isPowerOfTwo(quantum)) { + return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')'; + } + return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum; + }, + alignMemory: function(target, quantum) { if (typeof quantum !== 'number') { quantum = '(quantum ? quantum : {{{ STACK_ALIGN }}})'; } - return target + ' = ' + Runtime.forceAlign(target, quantum); + return target + ' = ' + RuntimeGenerator.forceAlign(target, quantum); }, // Given two 32-bit unsigned parts of an emulated 64-bit number, combine them into a JS number (double). @@ -95,6 +106,18 @@ function unInline(name_, params) { return ret; } +var Compiletime = { + isPointerType: isPointerType, + isStructType: isStructType, + + isNumberType: function(type) { + return type in Compiletime.INT_TYPES || type in Compiletime.FLOAT_TYPES; + }, + + INT_TYPES: set('i1', 'i8', 'i16', 'i32', 'i64'), + FLOAT_TYPES: set('float', 'double'), +}; + var Runtime = { // When a 64 bit long is returned from a compiled function the least significant // 32 bit word is passed in the return value, but the most significant 32 bit @@ -112,27 +135,6 @@ var Runtime = { STACKTOP = stackTop; }, - forceAlign: function(target, quantum) { - quantum = quantum || {{{ QUANTUM_SIZE }}}; - if (quantum == 1) return target; - if (isNumber(target) && isNumber(quantum)) { - return Math.ceil(target/quantum)*quantum; - } else if (isNumber(quantum) && isPowerOfTwo(quantum)) { - return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')'; - } - return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum; - }, - - isNumberType: function(type) { - return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES; - }, - - isPointerType: isPointerType, - isStructType: isStructType, - - INT_TYPES: set('i1', 'i8', 'i16', 'i32', 'i64'), - FLOAT_TYPES: set('float', 'double'), - // Imprecise bitops utilities or64: function(x, y) { var l = (x | 0) | (y | 0); @@ -216,10 +218,10 @@ var Runtime = { type.flatIndexes = type.fields.map(function(field) { index++; var size, alignSize; - if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) { + if (Compiletime.isNumberType(field) || Compiletime.isPointerType(field)) { size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s. alignSize = Runtime.getAlignSize(field, size); - } else if (Runtime.isStructType(field)) { + } else if (Compiletime.isStructType(field)) { if (field[1] === '0') { // this is [0 x something]. When inside another structure like here, it must be at the end, // and it adds no size From 8a5c20aaf55b6afbdca5c82c26f5f69a4de8fc7e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Aug 2014 14:47:40 -0700 Subject: [PATCH 11/60] add settings.js note of when we are running fastcomp --- emcc | 2 ++ src/settings.js | 1 + 2 files changed, 3 insertions(+) diff --git a/emcc b/emcc index 7cf67b75cc65e..67ddaeee6aa76 100755 --- a/emcc +++ b/emcc @@ -986,6 +986,8 @@ try: if js_opts: shared.Settings.RUNNING_JS_OPTS = 1 + shared.Settings.RUNNING_FASTCOMP = fastcomp + shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION shared.Settings.OPT_LEVEL = opt_level shared.Settings.DEBUG_LEVEL = debug_level diff --git a/src/settings.js b/src/settings.js index 59bc47f40ffad..42174ce9f9258 100644 --- a/src/settings.js +++ b/src/settings.js @@ -539,6 +539,7 @@ var NO_DYNAMIC_EXECUTION = 0; // When enabled, we do not emit eval() and new Fun // privileged firefox app, etc.) var RUNNING_JS_OPTS = 0; // whether js opts will be run, after the main compiler +var RUNNING_FASTCOMP = 1; // whether we are running the fastcomp backend var COMPILER_ASSERTIONS = 0; // costly (slow) compile-time assertions var COMPILER_FASTPATHS = 1; // use fast-paths to speed up compilation From cdb7dad8db02dffd252407e5f6c0a9e3509e7fc9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Aug 2014 14:48:51 -0700 Subject: [PATCH 12/60] move imprecise bitops runtime utils into non-fastcomp --- src/runtime.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime.js b/src/runtime.js index b86ba0bcfa8ab..370bc0df577f2 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -135,6 +135,7 @@ var Runtime = { STACKTOP = stackTop; }, +#if RUNNING_FASTCOMP == 0 // Imprecise bitops utilities or64: function(x, y) { var l = (x | 0) | (y | 0); @@ -151,6 +152,7 @@ var Runtime = { var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296; return l + h; }, +#endif //! Returns the size of a type, as C/C++ would have it (in 32-bit), in bytes. //! @param type The type, by name. From 06c663933f73c496eff0e84a437d5dcd63f70397 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Aug 2014 14:56:34 -0700 Subject: [PATCH 13/60] clean up dedup and set appearance in runtime --- src/runtime.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime.js b/src/runtime.js index 370bc0df577f2..31cea604041a8 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -189,9 +189,9 @@ var Runtime = { return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE); }, +#if RUNNING_FASTCOMP == 0 dedup: dedup, - - set: set, +#endif STACK_ALIGN: {{{ STACK_ALIGN }}}, From c6f531140114e3e0f6147ae0d3831619b79fb60e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Aug 2014 14:58:07 -0700 Subject: [PATCH 14/60] add structure alignment code to runtime only in non-fastcomp --- src/runtime.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime.js b/src/runtime.js index 31cea604041a8..cbb82be874418 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -208,6 +208,7 @@ var Runtime = { return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE); }, +#if RUNNING_FASTCOMP == 0 // Calculate aligned size, just like C structs should be. TODO: Consider // requesting that compilation be done with #pragma pack(push) /n #pragma pack(1), // which would remove much of the complexity here. @@ -340,6 +341,7 @@ var Runtime = { } return ret; }, +#endif dynCall: function(sig, ptr, args) { if (args && args.length) { From 97e2a795a958a322fb4112ad85a58e6f9d103b8f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 21 Aug 2014 16:45:19 -0700 Subject: [PATCH 15/60] add NO_FILESYSTEM and NO_BROWSER options, to reduce file size in cases where those functionalities are not necessary --- src/compiler.js | 4 ++++ src/library.js | 18 ++++++++++++++++++ src/modules.js | 28 +++++++++++++++++++--------- src/settings.js | 7 +++++++ tests/test_other.py | 25 +++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/compiler.js b/src/compiler.js index 3a0886fe39647..9e062d6f0d096 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -180,6 +180,10 @@ RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; if (SAFE_HEAP) USE_BSS = 0; // must initialize heap for safe heap +if (NO_BROWSER) { + DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.filter(function(func) { return func !== '$Browser' }); +} + // Settings sanity checks assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4'); diff --git a/src/library.js b/src/library.js index f656ec8877f2e..f31370855522e 100644 --- a/src/library.js +++ b/src/library.js @@ -2521,6 +2521,7 @@ LibraryManager.library = { }, puts__deps: ['fputs', 'fputc', 'stdout'], puts: function(s) { +#if NO_FILESYSTEM == 0 // int puts(const char *s); // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html // NOTE: puts() always writes an extra newline. @@ -2532,6 +2533,14 @@ LibraryManager.library = { var newlineRet = _fputc({{{ charCode('\n') }}}, stdout); return (newlineRet < 0) ? -1 : ret + 1; } +#else + // extra effort to support puts, even without a filesystem. very partial, very hackish + var result = Pointer_stringify(s); + var string = result.substr(0); + if (string[string.length-1] === '\n') string = string.substr(0, string.length-1); // remove a final \n, as Module.print will do that + Module.print(string); + return result.length; +#endif }, fread__deps: ['$FS', 'read'], fread: function(ptr, size, nitems, stream) { @@ -2818,8 +2827,17 @@ LibraryManager.library = { printf: function(format, varargs) { // int printf(const char *restrict format, ...); // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html +#if NO_FILESYSTEM == 0 var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}}; return _fprintf(stdout, format, varargs); +#else + // extra effort to support printf, even without a filesystem. very partial, very hackish + var result = __formatString(format, varargs); + var string = intArrayToString(result); + if (string[string.length-1] === '\n') string = string.substr(0, string.length-1); // remove a final \n, as Module.print will do that + Module.print(string); + return result.length; +#endif }, dprintf__deps: ['_formatString', 'write'], dprintf: function(fd, format, varargs) { diff --git a/src/modules.js b/src/modules.js index fd7b212417b4c..3db6663c02bdd 100644 --- a/src/modules.js +++ b/src/modules.js @@ -427,14 +427,24 @@ var LibraryManager = { var libraries = [ 'library.js', - 'library_path.js', - 'library_fs.js', - 'library_idbfs.js', - 'library_memfs.js', - 'library_nodefs.js', - 'library_sockfs.js', - 'library_tty.js', - 'library_browser.js', + ]; + if (!NO_FILESYSTEM) { + libraries = libraries.concat([ + 'library_path.js', + 'library_fs.js', + 'library_idbfs.js', + 'library_memfs.js', + 'library_nodefs.js', + 'library_sockfs.js', + 'library_tty.js', + ]); + } + if (!NO_BROWSER) { + libraries = libraries.concat([ + 'library_browser.js', + ]); + } + libraries = libraries.concat([ 'library_sdl.js', 'library_gl.js', 'library_glut.js', @@ -449,7 +459,7 @@ var LibraryManager = { 'library_html5.js', 'library_signals.js', 'library_async.js' - ].concat(additionalLibraries); + ]).concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { var filename = libraries[i]; diff --git a/src/settings.js b/src/settings.js index 42174ce9f9258..16f68c959da3f 100644 --- a/src/settings.js +++ b/src/settings.js @@ -346,6 +346,13 @@ var MEMFS_APPEND_TO_TYPED_ARRAYS = 0; // If set to nonzero, MEMFS will always ut // for appending data to files. The default behavior is to use typed arrays for files // when the file size doesn't change after initial creation, and for files that do // change size, use normal JS arrays instead. +var NO_FILESYSTEM = 0; // If set, does not build in any filesystem support. Useful if you are just doing pure + // computation, but not reading files or using any streams (including fprintf, and other + // stdio.h things) or anything related. The one exception is there is partial support for printf, + // and puts, hackishly. +var NO_BROWSER = 0; // If set, disables building in browser support using the Browser object. Useful if you are + // just doing pure computation in a library, and don't need any browser capabilities like a main loop + // (emscripten_set_main_loop), or setTimeout, etc. var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss // When enabled, 0-initialized globals are sorted to the end of the globals list, diff --git a/tests/test_other.py b/tests/test_other.py index 5c8ec7a3827b7..45fd7f2c0e32a 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -3977,6 +3977,31 @@ def get_size(name): test([]) test(['-O1']) + def test_no_nuthin(self): + def test(opts, ratio): + print opts + def get_size(name): + return os.stat(name).st_size + sizes = {} + def do(name, moar_opts): + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', name + '.js'] + opts + moar_opts).communicate() + sizes[name] = get_size(name + '.js') + self.assertContained('hello, world!', run_js(name + '.js')) + do('normal', []) + do('no_fs', ['-s', 'NO_FILESYSTEM=1']) + do('no_browser', ['-s', 'NO_BROWSER=1']) + do('no_nuthin', ['-s', 'NO_FILESYSTEM=1', '-s', 'NO_BROWSER=1']) + print ' ', sizes + assert sizes['no_fs'] < sizes['normal'] + assert sizes['no_browser'] < sizes['normal'] + assert sizes['no_nuthin'] < sizes['no_fs'] + assert sizes['no_nuthin'] < sizes['no_browser'] + assert sizes['no_nuthin'] < ratio*sizes['normal'] + test([], 0.66) + test(['-O1'], 0.66) + test(['-O2'], 0.50) + test(['-O3', '--closure', '1'], 0.60) + def test_stat_fail_alongtheway(self): open('src.cpp', 'w').write(r''' #include From 6dc95a7a382bf08039c52bb9ff36fda1d42d06b0 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Fri, 22 Aug 2014 09:48:27 +1000 Subject: [PATCH 16/60] Fixes to home page layout, size of inline code text, emcc final updates, improvements to tutorial and downloads --- .../emscripten_sphinx_rtd_theme/layout.html | 1 + .../static/css/theme.css | 17 ++- site/source/docs/getting_started/FAQ.rst | 2 + site/source/docs/getting_started/Tutorial.rst | 104 ++++++++---------- .../source/docs/getting_started/downloads.rst | 28 +++-- ...ing_started_with_emscripten_and_vs2010.rst | 22 +++- site/source/docs/getting_started/index.rst | 7 +- .../about_emscripten.rst | 2 +- .../docs/introducing_emscripten/index.rst | 8 +- site/source/docs/site/about.rst | 21 ++-- site/source/docs/tools_reference/emcc.rst | 3 +- site/source/docs/tools_reference/emsdk.rst | 2 +- site/source/home_page_layout.html | 6 +- site/source/index.rst | 14 +-- 14 files changed, 138 insertions(+), 99 deletions(-) diff --git a/site/source/_themes/emscripten_sphinx_rtd_theme/layout.html b/site/source/_themes/emscripten_sphinx_rtd_theme/layout.html index 2315ad930aaaf..5c25cb145b04e 100644 --- a/site/source/_themes/emscripten_sphinx_rtd_theme/layout.html +++ b/site/source/_themes/emscripten_sphinx_rtd_theme/layout.html @@ -98,6 +98,7 @@ {% set toctree = toctree(maxdepth=4, collapse=False, includehidden=True) %} {% if toctree %} {{ toctree }} + Index {% else %}
{{ toc }}
diff --git a/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css b/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css index 8775c04111263..fc6431dc9d294 100644 --- a/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css +++ b/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css @@ -37,7 +37,22 @@ body{ background:#edf0f2 } -.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980b9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27ae60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#e74c3c !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}code,.rst-content tt{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:"Inconsolata","Consolata","Monaco",monospace;color:#e74c3c;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px} +.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980b9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27ae60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#e74c3c !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%} + +code, .rst-content tt + { + white-space:nowrap; + max-width:100%; + background:#fff; + border:solid 1px #e1e4e5; + /* font-size:75%; */ + font-size:90%; + padding:0 5px; + font-family:"Inconsolata","Consolata","Monaco",monospace;color:#e74c3c; + overflow-x:auto + } + +code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px} .wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li { list-style:disc;margin-left:24px} diff --git a/site/source/docs/getting_started/FAQ.rst b/site/source/docs/getting_started/FAQ.rst index 5046ed0b8901f..43588b5aa83c8 100644 --- a/site/source/docs/getting_started/FAQ.rst +++ b/site/source/docs/getting_started/FAQ.rst @@ -173,6 +173,8 @@ FAQ (wiki-import) **A.** This is a limitation of the le32 frontend in clang. You can use the x86 frontend instead by compiling with ``EMCC_LLVM_TARGET=i386-pc-linux-gnu`` in the environment (however you will lose the advantages of le32 which includes better alignment of doubles). +.. _faq-when-safe-to-call-compiled-functions: + - **Q.** I am building a library, and sometimes I get an error when I call a compiled function before the page fully loaded. How can I tell when is safe to call it? **A.** The easiest way to find out when loading is complete (which is asynchronous, as it often requires loading files, such as the .mem file or preloade files), is to just add a ``main()`` function. It will be called when it is safe to do so, after startup is complete, so that is a signal that it is safe to call any compiled method. diff --git a/site/source/docs/getting_started/Tutorial.rst b/site/source/docs/getting_started/Tutorial.rst index 0a32173d14e63..a65eb01800512 100644 --- a/site/source/docs/getting_started/Tutorial.rst +++ b/site/source/docs/getting_started/Tutorial.rst @@ -1,32 +1,30 @@ .. _Tutorial: -============================================ -Emscripten Tutorial (under-construction) -============================================ - -**Using Emscripten is, at a base level, fairly simple. This tutorial takes you through the steps needed to compile your first Emscripten examples from the command line. It also shows how to preload files and set the compiler optimization flags.** +====================================== +Emscripten Tutorial (ready-for-review) +====================================== -.. note:: We don't cover it in this tutorial, but Emscripten is also integrated with Microsoft Visual Studio 2010. +**Using Emscripten is, at a base level, fairly simple. This tutorial takes you through the steps needed to compile your first Emscripten examples from the command line. It also shows how to work with files and set the main compiler optimization flags.** - The :term:`vs-tool` plugin is automatically deployed by the :term:`Windows NSIS Installer Emscripten SDK` if *Visual Studio 2010* is present on your system. This adds an 'Emscripten' configuration to the list of available Solution Configurations in Visual Studio. Activate this configuration for a solution/project to make Visual Studio run the project build through Emscripten, producing **.html** or **.js** output depending on the configured project properties. +.. tip:: Check out :ref:`this topic ` if you want to use *Emscripten* with Microsoft *Visual Studio 2010*. First things first ====================== -Make sure you have :ref:`downloaded and installed ` Emscripten (the exact approach for doing this will depend your operating system: Windows, Mac or Linux). +Make sure you have :ref:`downloaded and installed ` Emscripten (the exact approach for doing this will depend your operating system: Linux, Windows, or Mac). -Emscripten is accessed using the :ref:`emcc `. This script invokes all the other tools needed to build your code, and can act as a drop-in replacement for a standard compiler like *gcc*. It is called on the command line using ``emcc`` or ``em++`` +Emscripten is accessed using the :ref:`emccdoc`. This script invokes all the other tools needed to build your code, and can act as a drop-in replacement for a standard compiler like *gcc*. It is called on the command line using ``./emcc`` or ``./em++``. -.. note:: On Mac OS X the tool is called using the slightly different syntax: ``./emcc`` or ``./em++`` (or even directly via Python: ``python emcc``). The remainder of this tutorial uses the Windows syntax (``emcc``). +.. note:: On Windows the tool is called using the slightly different syntax: ``emcc`` or ``em++``. The remainder of this tutorial uses the Linux approach (``./emcc``). For the next section you will need to open a command prompt: - On Linux or Mac OS X, open a *Terminal*. - On Windows open the :ref:`Emscripten Command Prompt `, a command prompt that has been pre-configured with the correct system paths and settings to point to the :term:`active ` Emscripten tools. To access this prompt, type **Emscripten** in the Windows 8 start screen, and then select the **Emscripten Command Prompt** option. -Navigate with the command prompt to the :term:`SDK root directory` for your target SDK. This is an SDK-version-specific folder below the :term:`emsdk root directory`, e.g.: **\\emscripten\\1.20.0\\**. +Navigate with the command prompt to the :term:`SDK root directory` for your target SDK. This is an SDK-version-specific folder below the :term:`emsdk root directory`: **/emscripten/1.20.0/**. -.. warning:: Emscripten test code must be built from the "SDK Root" above (some of the code is dependent on file locations, and will build but not run if compiled from another location). +.. note:: The tests should be compiled from the "SDK Root" directory. This is required because some tests load files, and the locations of these files within Emscripten's virtual file system root is relative to the current directory at build time. Verifying Emscripten @@ -34,33 +32,32 @@ Verifying Emscripten If you haven't run Emscripten before, run it now with: :: - emcc -v + ./emcc -v If the output contains warnings about missing tools, see :ref:`verifying-the-emscripten-environment` for debugging help. Otherwise continue to the next sections where we'll build some code. Running Emscripten -====================================== +================== -You can now compile your first C++ file to JavaScript! +You can now compile your first C++ file to JavaScript. First, lets have a look at the file to be compiled: **hello_world.cpp**. This is the simplest test code in the SDK, and as you can see, all it does is print "hello, world!" to the console and then exit. .. include:: ../../../../tests/hello_world.cpp :literal: - -To build the JavaScript version of this code we simply specify the C++ file after *emcc*: :: +To build the JavaScript version of this code, simply specify the C++ file after *emcc*: :: - emcc tests/hello_world.cpp + ./emcc tests/hello_world.cpp There should now be an **a.out.js** file in the current directory. Run it using :term:`node.js`: :: - node a.out.js + ./node a.out.js This prints "hello, world!" to the console, as expected. @@ -68,19 +65,18 @@ This prints "hello, world!" to the console, as expected. - Generating HTML -====================================== +=============== -Emscripten can also generate HTML for testing embedded JavaScript. To generate HTML, use the ``-o`` (output) command and specify an html file as the target file: :: +Emscripten can also generate HTML for testing embedded JavaScript. To generate HTML, use the ``-o`` (:ref:`output `) command and specify an html file as the target file: :: - emcc tests/hello_world.cpp -o hello.html + ./emcc tests/hello_world.cpp -o hello.html Open the web page in a web browser. As you can see, the framework defines a text area for displaying the output of the ``printf()`` calls in the native code. -The HTML isn't limited just to just displaying text. You can also use the SDL API to show a colored cube in a Canvas element (on browsers that support it). For an example, build the **hello_world_sdl.cpp** test code and then refresh the browser: :: +The HTML output isn't limited just to just displaying text. You can also use the SDL API to show a colored cube in a Canvas element (on browsers that support it). For an example, build the `hello_world_sdl.cpp `_ test code and then refresh the browser: :: - emcc tests/hello_world_sdl.cpp -o hello.html + ./emcc tests/hello_world_sdl.cpp -o hello.html The source code for the second example is given below: @@ -89,15 +85,15 @@ The source code for the second example is given below: Using files -====================================== +=========== -Your C/C++ code can access files using the normal libc API (stdio: ``fopen``, etc.). +.. note:: Your C/C++ code can access files using the normal libc stdio API (``fopen``, ``fclose``, etc.) -JavaScript is usually run in the sandboxed environment of a web browser, without direct access to the local filesystem. Emscripten simulates a file system which you can access from the compiled code using the normal libc API. Files that you want to access should be :ref:`preloaded ` or :ref:`embedded ` into the virtual file system. +JavaScript is usually run in the sandboxed environment of a web browser, without direct access to the local file system. Emscripten simulates a file system which you can access from your compiled C/C++ code using the normal libc stdio API. -Preloading generates a virtual filesystem that corresponds to the filesystem structure at *compile* time, relative to the current directory. +Files that you want to access should be :ref:`preloaded ` or :ref:`embedded ` into the virtual file system. Preloading (or embedding) generates a virtual file system that corresponds to the file system structure at *compile* time, *relative to the current directory*. -.. todo:: **HamishW** When filesystem guide updated may be a better link for preloading and embedding than the emcc links above. These might even be better as term links in glossary. +.. todo:: **HamishW** When filesystem guide updated may be a better link for preloading and embedding than the *emcc* links above. These might even be better as term links in glossary. The `hello_world_file.cpp `_ example shows how to load a file (both the test code and the file to be loaded shown below): @@ -107,7 +103,11 @@ The `hello_world_file.cpp `_. We compile the example from the directory "above" **tests** to ensure that the text file is stored at this location in the virtual filesystem. +.. note:: The example expects to be able to load a file located at **tests/hello_world_file.txt**: :: + + FILE *file = fopen("tests/hello_world_file.txt", "rb"); + + We compile the example from the directory "above" **tests** to ensure that virtual filesystem is created with the correct structure relative to the compile-time directory. The following command is used to preload the data file. The ``--preload-file`` option will automatically preload the file before running the compiled code. This is useful because loading data from the network cannot be done synchronously in browsers outside Web Workers. :: @@ -118,36 +118,23 @@ Open ``hello.html`` in the *Firefox web browser* to see the data from **hello_wo .. note:: Unfortunately *Chrome* and *Internet Explorer* do not support ``file://`` :term:`XHR` requests, and can't directly load the local file in which preloaded data is stored. For these browsers you'll need to serve the files using a webserver. The easiest way to do this is to use the python **SimpleHTTPServer** (in the current directory do ``python -m SimpleHTTPServer 8080`` and then open ``localhost:8080/hello.html``). ----- - -For an example of how to load files with SDL, check out `tests/hello_image_sdl.c `_: - -.. include:: ../../../../tests/hello_image_sdl.c - :literal: - -The source code expects a file **screenshot.jpg** in the current directory. As discussed above, this means that we need to compile the source and preload from the same directory that contains the screenshot. Change to the **tests/** directory and run: :: - - emcc hello_image_sdl.c --preload-file screenshot.jpg -o a.html - -Then browse to **a.html** (again, noting that you will need to use either Mozilla Firefox or a web server). You should see a pretty cool image displayed. - For more information about working with the file system see the :ref:`Filesystem-Guide`, :ref:`Filesystem-API` and :ref:`Synchronous-virtual-XHR-backed-file-system-usage`. Optimizing code -====================================== +=============== -Emscripten, like *gcc*, generates unoptimized code by default. You can generate slightly-optimized code with the ``-O1`` command line argument (run the test code from the :term:`SDK root directory`): :: +Emscripten, like *gcc*, generates unoptimized code by default. You can generate :ref:`slightly-optimized ` code with the ``-O1`` command line argument (run the test code from the :term:`SDK root directory`): :: - emcc -O1 tests/hello_world.cpp + ./emcc -O1 tests/hello_world.cpp The "hello world" code created in **a.out.js** doesn't really need to be optimized, so you won't see a difference in speed when compared to the unoptimized version. However, you can compare the generated code to see the differences. ``-O1`` applies several minor optimizations and removes some runtime assertions. For example, ``printf`` will have been replaced by ``puts`` in the generated code. -The optimizations provided by ``-O2`` are much more aggressive. If you run the following command and inspect the generated code (**a.out.js**) you will see that it looks very different: :: +The optimizations provided by ``-O2`` (see :ref:`here `) are much more aggressive. If you run the following command and inspect the generated code (**a.out.js**) you will see that it looks very different: :: - emcc -O2 tests/hello_world.cpp + ./emcc -O2 tests/hello_world.cpp For more information about compiler optimization options see :ref:`Optimizing-Code` and the :ref:`emcc tool reference `. @@ -155,19 +142,19 @@ For more information about compiler optimization options see :ref:`Optimizing-Co .. _running-emscripten-tests: Running the Emscripten Test Suite and Benchmarks -============================================================================ +================================================ Emscripten has an extensive test suite at `tests/runner.py `_. To run every test (this may take several hours), simply call the test script: :: python tests/runner.py -The individual tests are listed in the different test suites - for example "test_hello_world" is defined in the `core test suite here `_. You can run individual tests as shown: :: +The individual tests are listed in the different test suites — for example "test_hello_world" is defined in the `core test suite here `_. You can run individual tests as shown: :: python tests/runner.py test_hello_world .. todo:: **HamishW** Confirm that this is how test suites are done. We really should have a stand alone topic for this and link to it at this point. -To view the generated code from that individual test, you can first set ``EMCC_DEBUG=1``. This is shown for both Windows and Linxu below: :: +To view the generated code from that individual test, you can first set ``EMCC_DEBUG=1``: :: # On Windows, use "set" to set and un-set the environment variable: set EMCC_DEBUG=1 @@ -190,7 +177,7 @@ Note that **Node.js** cannot run all of the tests in the suite; if you care abou .. _running-emscripten-benchmarks: -To run the Emscripten benchmark tests, enter the following command: :: +To run the Emscripten *benchmark* tests, enter the following command: :: python tests/runner.py benchmark @@ -199,11 +186,12 @@ This will compile a sequence of benchmarks and run them several times, reporting General tips and next steps -====================================== +=========================== This tutorial walked you through your first steps in calling Emscripten from the command line. There is, of course, far more you can do with the tool. Below are other general tips for using Emscripten: -- This site has lots more information about :ref:`compiling and building projects `, :ref:`integrating your native code with the web environment `, :ref:`packaging your code ` and publishing. -- The Emscripten test suite is a great place to look for examples of how to use Emscripten. For example, if you want to better understand how the *emcc* ``--pre-js`` option works, search for ``--pre-js`` in the test suite: the test suite is extensive and there are likely to be at least some examples. -- To learn how to use Emscripten in advanced ways, read :ref:`src/settings.js ` and :ref:`emcc ` which describe the compiler options, and :ref:`emscripten-h` which describes JavaScript-specific C APIs that your C/C++ programs can use when compiled with Emscripten. -- When in doubt, :ref:`get in touch `! +- This site has lots more information about :ref:`compiling and building projects `, :ref:`integrating your native code with the web environment `, :ref:`packaging your code ` and publishing. +- The Emscripten test suite is a great place to look for examples of how to use Emscripten. For example, if you want to better understand how the *emcc* ``--pre-js`` option works, search for ``--pre-js`` in the test suite: the test suite is extensive and there are likely to be at least some examples. +- To learn how to use Emscripten in advanced ways, read :ref:`src/settings.js ` and :ref:`emcc ` which describe the compiler options, and :ref:`emscripten-h` which describes JavaScript-specific C APIs that your C/C++ programs can use when compiled with Emscripten. +- Read the :ref:`FAQ`. +- When in doubt, :ref:`get in touch `! diff --git a/site/source/docs/getting_started/downloads.rst b/site/source/docs/getting_started/downloads.rst index 3ba51b89ad757..27085239dd816 100644 --- a/site/source/docs/getting_started/downloads.rst +++ b/site/source/docs/getting_started/downloads.rst @@ -64,10 +64,10 @@ The *Portable Emscripten SDK* is a no-installer version of the SDK package. It i First check the :ref:`Platform-specific notes ` below and install any prerequisites. -Install the SDK using the following steps: +Install or update the SDK using the following steps: 1. Download and unzip the portable SDK package to a directory of your choice. This directory will contain the Emscripten SDK. -#. Open a command prompt inside the SDK directory and run the following :ref:`emsdk ` commands to get the latest SDK tools and set them as :term:`active `. +#. Open a command prompt inside the SDK directory and run the following :ref:`emsdk ` commands to get the latest tools from Github and set them as :term:`active `. .. note:: On Windows, invoke the tool with **emsdk** instead of **./emsdk**: @@ -80,13 +80,20 @@ Install the SDK using the following steps: ./emsdk install latest # Make the "latest" SDK "active" - ./emsdk activate latest - -Whenever you change the location of the Portable SDK (e.g. take it to another computer), re-run the final command: ``./emsdk activate latest``. - -.. tip:: The instructions above can also be used to get new SDKs, as they are released. + ./emsdk activate latest +#. **Linux and Mac OS X only:** Call ``source ./emsdk_env.sh`` after ``activate`` to set the system path to the active version of Emscripten: + :: + + # Set the current Emscripten path on Linux/Mac OS X + source ./emsdk_env.sh + + This step is not required on Windows because calling the ``activate`` command also sets the correct system path (this is not possible on Linux due to security restrictions). + +Whenever you change the location of the Portable SDK (e.g. take it to another computer), re-run the ``./emsdk activate latest`` command (and ``source ./emsdk_env.sh`` for Linux). + + .. _platform-notes-installation_instructions-portable-SDK: Platform-specific notes @@ -112,7 +119,9 @@ Mac OS X Linux ++++++++ -.. note:: Pre-built binaries of tools are not available on Linux. Installing a tool will automatically clone and build that tool from the sources inside the **emsdk** directory. *Emsdk* does not interact with Linux package managers on the behalf of the user, nor does it install any tools to the system. All file changes are done inside the **emsdk/** directory. +**Pre-built binaries of tools are not available on Linux.** Installing a tool will automatically clone and build that tool from the sources inside the **emsdk** directory. + +.. note:: *Emsdk* does not install any tools to the system, or otherwise interact with Linux package managers. All file changes are done inside the **emsdk/** directory. - The system must have a working :ref:`compiler-toolchain` (because *emsdk* builds software from the source): @@ -171,6 +180,9 @@ Type the following (omitting comments) on the :ref:`Emscripten Command Prompt ` (or even your own fork). Check out all the possibilities in the :ref:`emsdk_howto`. diff --git a/site/source/docs/getting_started/getting_started_with_emscripten_and_vs2010.rst b/site/source/docs/getting_started/getting_started_with_emscripten_and_vs2010.rst index f3818c9c4a5d9..6ce6f56d29daa 100644 --- a/site/source/docs/getting_started/getting_started_with_emscripten_and_vs2010.rst +++ b/site/source/docs/getting_started/getting_started_with_emscripten_and_vs2010.rst @@ -4,8 +4,27 @@ Getting started using Emscripten from the Visual Studio 2010 IDE (under-construction) =========================================================================================== +Windows Developers who want to use an IDE can develop and compile their Emscripten projects from `Microsoft Visual Studio 2010 `_. This article shows you how. -To build a Visual Studio solution using the Emscripten toolchain, select the "Emscripten" configuration from the Configuration Manager dropdown as the active configuration, and choose Build Solution (F7). +.. note:: Visual Studio 2011 and 2012 are not supported. + +Integrating Emscripten and Visual Studio +======================================== + +The integration is enabled the :term:`vs-tool` plugin. + +This plugin is automatically deployed by the :term:`Windows NSIS Installer Emscripten SDK` if *Visual Studio 2010* is present on your system. It is also possible to :ref:`manually integrate Emscripten into Visual Studio 2010 `. + +The *vs-tool* plugin adds an 'Emscripten' configuration to the list of available *Solution Configurations* in Visual Studio. Activate this configuration for a solution/project to make Visual Studio run the project build through Emscripten, producing **.html** or **.js** output depending on the configured project properties. + +How to build a Visual Studio solution using Emscripten +================================================================================ + +First select the "Emscripten" configuration from the Configuration Manager dropdown as the active configuration, and choose Build Solution (F7). + + +How to launch a project in a web browser from Visual Studio +================================================================================ To launch a project directly to a web browser from Visual Studio, right-click on the project to run, choose "Set as Startup Project", and select Start without Debugging (Ctrl+F5). This should launch the generated .html file to the browser you specified in EMCC\_WEBBROWSER\_EXE. A bug(?) in Visual Studio causes a "Executable for Debug Session" dialog to occasionally open up when you hit Ctrl+F5. This can be ignored by clicking Yes, then No, or simply by hitting Esc and then tapping Ctrl+F5 again. @@ -17,3 +36,4 @@ Empty. After this, you can switch between building the solution for Win32 and Em When you want to create a new Visual Studio project for Emscripten, we recommend you start with a Visual C++ Empty Project. This will create a new project for the Win32 platform. Then convert that project for Emscripten as outlined in the previous paragraph. + diff --git a/site/source/docs/getting_started/index.rst b/site/source/docs/getting_started/index.rst index bcf71b4b17b28..6b579725afc7c 100644 --- a/site/source/docs/getting_started/index.rst +++ b/site/source/docs/getting_started/index.rst @@ -1,9 +1,14 @@ .. _getting-started-index: ===================================== -Getting Started (under-construction) +Getting Started (ready-for-review) ===================================== +Now you know why Emscripten is :ref:`right for you `, it's time to *get started*. + +This section provides a walk-through of :ref:`downloading and installing the SDK ` and the basics of :ref:`using the Emscripten toolchain `. The general :ref:`FAQ` answers many common questions about setting up and using Emscripten. + +We also explain where to :ref:`Report Bugs ` in the toolchain and the site, and how to use Emscripten with :ref:`Visual Studio 2010 ` (Windows only). .. toctree:: :maxdepth: 1 diff --git a/site/source/docs/introducing_emscripten/about_emscripten.rst b/site/source/docs/introducing_emscripten/about_emscripten.rst index d7fc0cc9f1ef4..d8361830fb5fb 100644 --- a/site/source/docs/introducing_emscripten/about_emscripten.rst +++ b/site/source/docs/introducing_emscripten/about_emscripten.rst @@ -54,7 +54,7 @@ The :ref:`emsdk` is used to manage multiple SDKs and tools, and to specify the p A number of other tools are not shown — for example, Java can optionally be used by *emcc* to run the :term:`closure compiler`, which can further decrease code size. -The whole toolchain is delivered in the :ref:`Emscripten SDK ` +The whole toolchain is delivered in the :ref:`Emscripten SDK `, and can be used on Linux, Windows or Mac OS X. Porting code to use Emscripten diff --git a/site/source/docs/introducing_emscripten/index.rst b/site/source/docs/introducing_emscripten/index.rst index 557cdc1699a53..e95c658861a15 100644 --- a/site/source/docs/introducing_emscripten/index.rst +++ b/site/source/docs/introducing_emscripten/index.rst @@ -1,8 +1,8 @@ -================================================= -Introducing Emscripten (under-construction) -================================================= +========================================= +Introducing Emscripten (ready-for-review) +========================================= -This section introduces Emscripten. It explains what the tool does, why it is needed, its limitations and its licensing. After reading, you will understand whether Emscripten is the right tool for you, and where to go if you have :ref:`further questions `. +This section explains what the Emscripten does, why it is needed, its limitations and its licensing. After reading, you will understand whether Emscripten is the right tool for you, and where to go if you have :ref:`further questions `. .. toctree:: :maxdepth: 1 diff --git a/site/source/docs/site/about.rst b/site/source/docs/site/about.rst index 41e7c3967c89f..3ab58e14b7b5c 100644 --- a/site/source/docs/site/about.rst +++ b/site/source/docs/site/about.rst @@ -28,11 +28,6 @@ By the end of the project all articles should be published and all of this page .. todo:: **HamishW** Delete this whole section at the end of the project. At that point there should only be HamishW markup for possible Todos. Note the search link immediately above too - this is to the kripken site and may need to change if the site moves. -Reporting bugs -============== - -Please :ref:`report documentation bugs ` as you would any other Emscripten bug. Help :ref:`fix them ` by updating existing documents or by creating new ones. - Searching the site ================== @@ -41,7 +36,19 @@ Searching returns only topics which contain **all** the specified keywords. .. tip:: Always start by searching for *single* words like "interacting" or "compiling". Generally this will be enough to find the relevant document. If not, you can refine the search by adding additional terms. -Note that searches that include characters like "-" and "+" will not work. There is no support for logical operators. +.. note:: Searches that include characters like "-" and "+" will not work. There is no support for logical operators. + +Reporting bugs +============== + +Please :ref:`report documentation bugs ` as you would any other Emscripten bug. Help :ref:`fix them ` by updating existing documents or by creating new ones. + +Contributing to the site +======================== + +:ref:`Contributions ` to this site (and indeed any part of Emscripten) are welcome! + +Check out the rest of this article for instructions on how to :ref:`build the site ` and :ref:`write and update articles `. .. _building-the-site: @@ -49,7 +56,7 @@ Note that searches that include characters like "-" and "+" will not work. There Building the site ================== -The site sources are in the Emscripten *incoming* branch, `site `_ directory. Changes should be committed to the incoming branch. +The site sources are stored on Github `here `_. Edits and additions should be submitted to this branch in the same way as any other change to the tool. The site is published to the **kripken/emscripten-site** *gh-pages* branch (Github pages). diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index 585910c85f002..8b3031c54e43b 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -277,7 +277,7 @@ Options that are modified or new in *emcc* are listed below: - ``0``: Do not emit a separate memory initialization file (default). Instead keep the static initialization inside the generated JavaScript as text. - ``1``: Emit a separate memory initialization file in binary format. This is more efficient than storing it as text inside JavaScript, but does mean you have another file to publish. The binary file will also be loaded asynchronously, which means ``main()`` will not be called until the file is downloaded and applied; you cannot call any C functions until it arrives. - .. note:: The :ref:`safest way ` to ensure that it is safe to call C functions (the initialisation file has loaded) is to call a notifier function from ``main()``. You might also call ``addOnPreMain`` from a :js:attr:`Module.preRun`. + .. note:: The :ref:`safest way ` to ensure that it is safe to call C functions (the initialisation file has loaded) is to call a notifier function from ``main()``. ``-Wno-warn-absolute-paths`` Suppress warnings about the use of absolute paths in ``-I`` and ``-L`` command line directives. This is used to hide the warnings and acknowledge that the explicit use of absolute paths is intentional. @@ -304,6 +304,7 @@ Options that are modified or new in *emcc* are listed below: ``--valid_abspath path`` Whitelist an absolute path to prevent warnings about absolute include paths. +.. _emcc-o-target: ``-o `` The ``target`` file name extension defines what type of output be generated: diff --git a/site/source/docs/tools_reference/emsdk.rst b/site/source/docs/tools_reference/emsdk.rst index ab411cf87ce08..11fed04b62a71 100644 --- a/site/source/docs/tools_reference/emsdk.rst +++ b/site/source/docs/tools_reference/emsdk.rst @@ -200,7 +200,7 @@ Toggle between different tools and SDK versions using the :term:`activate Emscripten is an LLVM-based project that compiles C/C++ into h
-