DEV Community

Cover image for low-level subset of JavaScript
ViperT
ViperT

Posted on • Edited on

low-level subset of JavaScript

I am working on a drawing editor for pixel art and NFTs that scale up to 6x6 times in Ultra HD 4K, and sometimes artworks in small size can be up to 512x512 of dimensions, this project is called https://pixa.pics/

Image description

The problem arise when we try to compute the colors when drawing or applying a filter intentionally with low-level javascript function in order to control deeply the fields of the pixels, but hey, let's make a simple computation, that's easy for a computer but for javascript lack of indication for the Javascript engine it can be really slow!

Image description

What was the solution without requiring to learn a lot of new things like webassembly, webgl, and so on would require?? EASY --> VERY SIMPLE, the solutions the mostly correct IMHO regarding performance was my disovery of asm.js and LLJS in fact if you have done some more "difficult" programming language you'll know that you have to specify what type of data is being processed and which way, you have to say if it is a short number, a number with decimal, or some text, and so on...

Here in Javascript you do it like this!


// Initianlize it with the type "Int" the "|" (bitwise) operator will make it be an entire number either positive or negative

var i = 0;
i = (i+1)|0;

// Inititalize it with the type "Unsigned Int", the operator looking like a thing that should seem fast simply tells it has to be POSITIVE when it leaves the precedent area at execution, it just make it positive always... Because passed after the before-lasting bit that tells the signed integer it can be positive or negative, it will require to store the variables into a double (which is like two times heavier to store) instead if it knows it will stay positive, it maybe doesn't have again to allocate useless ressources

var x = i >>> 0;

// This code will make the left side of the "0xFF" (being 255 in hexadecimal) a number between 0 and 255, very useful it tells in this example the compiler to not need to allocate a too large variable deep-down in the level of the processing unit...

var y = x & 0xFF;

..."Just lookat asm.js and LLJS +ArrayBuffer/Dataview/TypedArray!!!"
Enter fullscreen mode Exit fullscreen mode

BONUS:

// http://michalbe.blogspot.com.br/2013/03/javascript-less-known-parts-bitwise.html
// http://jsperf.com/bitwise-vs-math-object
// http://united-coders.com/christian-harms/results-for-game-for-forfeits-and-the-winner-is/
// https://mudcu.be/journal/2011/11/bitwise-gems-and-other-optimizations/
// https://dreaminginjavascript.wordpress.com/2009/02/09/bitwise-byte-foolish/
// http://jsperf.com/math-min-max-vs-ternary-vs-if/24

"use strict";

var PI = Math.PI;
var HALF_PI = PI * 0.5;
var TWO_PI = PI * 2;
var RADIAN = 180 / PI;

// Max int for simple bitwise operations
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers
var MAX_SIGNED_32_BIT_INT = Math.pow(2, 31) - 1;
var MIN_SIGNED_32_BIT_INT = ~MAX_SIGNED_32_BIT_INT;

// ECMAScript 6 - MIN/MAX safe integer
if (Number.MAX_SAFE_INTEGER === void 0) {
  Number.MIN_SAFE_INTEGER = -( Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1 );
}

function ABS_INT(n) {
  return (n ^ (n >> 31)) - (n >> 31);
}

function MAX_INT(a, b) {
  return a - ((a - b) & ((a - b) >> 31));
  //return a ^ ((a ^ b) & -(a < b));
  //  var c = a - b;
  //  return a - ((c >> 31) & 0x1) * c;  
}

function MIN_INT(a, b) {
  return a - ((a - b) & ((b - a) >> 31));
  // return b ^ ((a ^ b) & -(a < b));
}

function CLAMP_INT( x, min, max ) {
  x = x - ((x - max) & ((max - x) >> 31));
  return x - ((x - min) & ((x - min) >> 31));
  //return ( n > max ) ? max : ( n < min ) ? n : min;
}

function IS_INT_POWER_OF_TWO( value ) {
  return ( value & ( value - 1 ) ) === 0 && value !== 0;
}

function PLUS_ONE_INT(n) { // slower than ++
  return -~n;
}

function MINUS_ONE_INT() { // slower than --
  return ~-n;
}

function IS_ODD_INT(n) {
  return (n & 1) === 1;
}

function ARRAY_SWAP_INT(array, i, j) {
  array[i] ^= array[j];
  array[j] ^= array[i];
  array[i] ^= array[j];
}

function HAS_SAME_SIGN(a, b) {
  return (a ^ b) >= 0;
}

function POW_OF_2_INT(n) { // === Math.pow(2, n)
  return 2 << (n - 1);
}

function AVG_INT(a, b) { // a + b / 2
  return (a + b) >> 1;
}

function TOGGLE_A_B_INT(n, a, b) { // if(x==a) x=b; if(x==b) x=a;
  return a ^ b ^ n;
}


function SET_BIT(n, bit) {
  return n | (1 << bit);
}

function CLEAR_BIT(n, bit) {
  return n & ~(1 << bit);
}

function MODULO_INT(numerator, divisor) { // 600% faster out of function than %
  return numerator & (divisor - 1);
} 
Enter fullscreen mode Exit fullscreen mode

https://gist.github.com/leodutra/63ca94fe86dcffee1bab (not mine)

Keep up the great work with this hints about performance, to us for a drawing software the 300% performance boost was enough to keep it mostly JS!

Top comments (0)