From 13d7930a4f7af22df75a9d5c4e446e06b8c24e19 Mon Sep 17 00:00:00 2001 From: Bernard Teo Date: Sun, 2 Apr 2017 22:41:18 +0800 Subject: [PATCH] do compilation and execution in a webworker, and prepare for interactive mode --- index-notworking.html | 2 +- jelly-bf-sync.js | 83 ++ jelly-bf-worker.js | 33 + jelly-bf-worker.max.js | 1664 ++++++++++++++++++++++++++++++++++++++++ jelly-bf-worker.min.js | 1 + join-worker.bat | 1 + main-old.js | 30 + main.js | 55 +- uglify-worker.bat | 1 + 9 files changed, 1867 insertions(+), 3 deletions(-) create mode 100644 jelly-bf-sync.js create mode 100644 jelly-bf-worker.js create mode 100644 jelly-bf-worker.max.js create mode 100644 jelly-bf-worker.min.js create mode 100644 join-worker.bat create mode 100644 main-old.js create mode 100644 uglify-worker.bat diff --git a/index-notworking.html b/index-notworking.html index 88a6dbc..af3d016 100644 --- a/index-notworking.html +++ b/index-notworking.html @@ -7,7 +7,7 @@ - +

Jelly Brainfuck Compiler

diff --git a/jelly-bf-sync.js b/jelly-bf-sync.js new file mode 100644 index 0000000..37440c2 --- /dev/null +++ b/jelly-bf-sync.js @@ -0,0 +1,83 @@ +var JellyBFSync={ + compile:function(str,options){ + return WebAssembly.Module(JellyBFCompiler.compile(str,options)); + }, + execute:function(module,inputuint8array,options){ + options.eof_value=options.eof_value||0; + var inputindex=0; + var outputdata=new ResizableUint8Array(); + var get_input=function(){ + if(inputindex this._data.length) { + var new_buffer = new ArrayBuffer(Math.max(this._data.length * 2, this._size + amount)); + var new_data = new Uint8Array(new_buffer); + for (var i = 0; i < this._size; ++i) { + new_data[i] = this._data[i]; + } + this._buffer = new_buffer; + this._data = new_data; + } +}; + +ResizableUint8Array.prototype.push = function(value) { + this.reserve_extra(1); + this._data[this._size++] = value; +}; + +ResizableUint8Array.prototype.append = function(value_uint8array) { + this.reserve_extra(value_uint8array.length); + for (var i = 0; i < value_uint8array.length; ++i) { + this._data[this._size++] = value_uint8array[i]; + } +}; + +ResizableUint8Array.prototype.pop = function() { + return this._data[--this._size]; +}; + +ResizableUint8Array.prototype.insert_arr = function(index, value_uint8array) { + this.reserve_extra(value_uint8array.length); + for (var i = this._size - 1; i >= index; --i) { + this._data[i + value_uint8array.length] = this._data[i]; + } + for (var i = 0; i < value_uint8array.length; ++i) { + this._data[index + i] = value_uint8array[i]; + } + this._size += value_uint8array.length; +}; + +ResizableUint8Array.prototype.toUint8Array = function() { + var ret_arr = new Uint8Array(this._size); + for (var i = 0; i < this._size; ++i) { + ret_arr[i] = this._data[i]; + } + return ret_arr; +}; + +var encodeUIntString = function(str) { + return new TextEncoder().encode(str); +}; + +var VLQEncoder = {}; + +VLQEncoder.encodeUInt = function(value) { + if (value < 0 || value !== Math.floor(value)) debugger; + var output = new ResizableUint8Array(); + while (true) { + var next_val = value % 128; + value = Math.floor(value / 128); + if (value > 0) { + output.push(128 + next_val); + } else { + output.push(next_val); + break; + } + } + return output.toUint8Array(); +}; + +VLQEncoder.encodeInt = function(value) { + if (value !== Math.floor(value)) debugger; + var output = new ResizableUint8Array(); + var is_neg = value < 0; + if (is_neg) value = -value - 1; + while (true) { + var next_val = value % 128; + value = Math.floor(value / 128); + if (value > 0 || next_val >= 64) { + if (is_neg) output.push(~next_val & 255); else output.push(128 + next_val); + } else { + if (is_neg) output.push(~next_val & 127); else output.push(next_val); + break; + } + } + return output.toUint8Array(); +}; + +var Wasm32VarType = { + i32: 127, + i64: 126, + f32: 125, + f64: 124, + anyfunc: 112, + func: 96, + none: 64 +}; + +var Wasm32ExternalKind = { + function: 0, + table: 1, + memory: 2, + global: 3 +}; + +var Wasm32TypeWriter = function(param_types, result_types) { + this._param_types = param_types ? param_types : []; + this._result_types = result_types ? result_types : []; +}; + +Wasm32TypeWriter.prototype.toUint8Array = function() { + var output = new ResizableUint8Array(); + output.push(Wasm32VarType.func); + output.append(VLQEncoder.encodeUInt(this._param_types.length)); + for (var i = 0; i < this._param_types.length; ++i) { + output.push(this._param_types[i]); + } + output.append(VLQEncoder.encodeUInt(this._result_types.length)); + for (var i = 0; i < this._result_types.length; ++i) { + output.push(this._result_types[i]); + } + return output.toUint8Array(); +}; + +var Wasm32FunctionWriter = function(type_index) { + this._type = type_index; +}; + +Wasm32FunctionWriter.prototype.toUint8Array = function() { + var output = new ResizableUint8Array(); + output.append(VLQEncoder.encodeUInt(this._type)); + return output.toUint8Array(); +}; + +var Wasm32CodeWriter = function(local_types) { + this._localTypes = local_types ? local_types : []; + this._data = new ResizableUint8Array(); + this._functionlinks = []; +}; + +Wasm32CodeWriter.prototype.setName = function(name) { + this._functionname = name; +}; + +Wasm32CodeWriter.prototype.setType = function(type) { + this._functiontype = type; +}; + +Wasm32CodeWriter.prototype.setLocalTypes = function(local_types) { + this._localTypes = local_types ? local_types : []; +}; + +Wasm32CodeWriter.instruction = { + unreachable: 0, + nop: 1, + block: 2, + loop: 3, + if: 4, + else: 5, + end: 11, + br: 12, + br_if: 13, + br_table: 14, + return: 15, + call: 16, + call_indirect: 17, + drop: 26, + select: 27, + get_local: 32, + set_local: 33, + tee_local: 34, + get_global: 35, + set_global: 36, + i32_load: 40, + i64_load: 41, + f32_load: 42, + f64_load: 43, + i32_load8_s: 44, + i32_load8_u: 45, + i32_load16_s: 46, + i32_load16_u: 47, + i64_load8_s: 48, + i64_load8_u: 49, + i64_load16_s: 50, + i64_load16_u: 51, + i64_load32_s: 52, + i64_load32_u: 53, + i32_store: 54, + i64_store: 55, + f32_store: 56, + f64_store: 57, + i32_store8: 58, + i32_store16: 59, + i64_store8: 60, + i64_store16: 61, + i64_store32: 62, + current_memory: 63, + grow_memory: 64, + i32_const: 65, + i64_const: 66, + f32_const: 67, + f64_const: 68, + i32_eqz: 69, + i32_eq: 70, + i32_ne: 71, + i32_add: 106, + i32_sub: 107, + i32_mul: 108 +}; + +Wasm32CodeWriter.prototype.writeRawBytes = function() { + for (var i = 0; i < arguments.length; ++i) { + if (!(arguments[i] >= 0 && arguments[i] < 256)) debugger; + this._data.push(arguments[i]); + } +}; + +Wasm32CodeWriter.prototype.writeUint8Array = function(arr) { + this._data.append(arr); +}; + +Wasm32CodeWriter.prototype.unreachable = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.unreachable); +}; + +Wasm32CodeWriter.prototype.nop = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.nop); +}; + +Wasm32CodeWriter.prototype.block = function(result_type) { + this.writeRawBytes(Wasm32CodeWriter.instruction.block, result_type); +}; + +Wasm32CodeWriter.prototype.loop = function(result_type) { + this.writeRawBytes(Wasm32CodeWriter.instruction.loop, result_type); +}; + +Wasm32CodeWriter.prototype.if = function(result_type) { + this.writeRawBytes(Wasm32CodeWriter.instruction.if, result_type); +}; + +Wasm32CodeWriter.prototype.else = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.else); +}; + +Wasm32CodeWriter.prototype.end = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.end); +}; + +Wasm32CodeWriter.prototype.br = function(relative_depth) { + this.writeRawBytes(Wasm32CodeWriter.instruction.br); + this.writeUint8Array(VLQEncoder.encodeUInt(relative_depth)); +}; + +Wasm32CodeWriter.prototype.br_if = function(relative_depth) { + this.writeRawBytes(Wasm32CodeWriter.instruction.br_if); + this.writeUint8Array(VLQEncoder.encodeUInt(relative_depth)); +}; + +Wasm32CodeWriter.prototype.return = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.return); +}; + +Wasm32CodeWriter.prototype.call = function(function_index_or_name) { + if (typeof function_index_or_name === "number") { + this.writeRawBytes(Wasm32CodeWriter.instruction.call); + this.writeUint8Array(VLQEncoder.encodeUInt(function_index_or_name)); + } else { + this.writeRawBytes(Wasm32CodeWriter.instruction.call); + this._functionlinks.push({ + location: this._data.size(), + name: function_index_or_name + }); + } +}; + +Wasm32CodeWriter.prototype.drop = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.drop); +}; + +Wasm32CodeWriter.prototype.select = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.select); +}; + +Wasm32CodeWriter.prototype.get_local = function(localidx) { + this.writeRawBytes(Wasm32CodeWriter.instruction.get_local); + this.writeUint8Array(VLQEncoder.encodeUInt(localidx)); +}; + +Wasm32CodeWriter.prototype.set_local = function(localidx) { + this.writeRawBytes(Wasm32CodeWriter.instruction.set_local); + this.writeUint8Array(VLQEncoder.encodeUInt(localidx)); +}; + +Wasm32CodeWriter.prototype.tee_local = function(localidx) { + this.writeRawBytes(Wasm32CodeWriter.instruction.tee_local); + this.writeUint8Array(VLQEncoder.encodeUInt(localidx)); +}; + +Wasm32CodeWriter.prototype.i32_load = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_load); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.f32_load = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.f32_load); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.f64_load = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.f64_load); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_load8_s = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_load8_s); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_load8_u = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_load8_u); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_load16_s = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_load16_s); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_load16_u = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_load16_u); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load8_s = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load8_s); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load8_u = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load8_u); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load16_s = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load16_s); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load16_u = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load16_u); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load32_s = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load32_s); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_load32_u = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_load32_u); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_store = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_store); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_store = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_store); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.f32_store = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.f32_store); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.f64_store = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.f64_store); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_store8 = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_store8); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i32_store16 = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_store16); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_store8 = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_store8); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_store16 = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_store16); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.i64_store32 = function(offset, log_align) { + log_align = log_align || 0; + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_store32); + this.writeUint8Array(VLQEncoder.encodeUInt(log_align)); + this.writeUint8Array(VLQEncoder.encodeUInt(offset)); +}; + +Wasm32CodeWriter.prototype.current_memory = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.current_memory, 0); +}; + +Wasm32CodeWriter.prototype.grow_memory = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.grow_memory, 0); +}; + +Wasm32CodeWriter.prototype.i32_const = function(val_i32) { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_const); + this.writeUint8Array(VLQEncoder.encodeInt(val_i32)); +}; + +Wasm32CodeWriter.prototype.i64_const = function(val_i64) { + this.writeRawBytes(Wasm32CodeWriter.instruction.i64_const); + this.writeUint8Array(VLQEncoder.encodeInt(val_i64)); +}; + +Wasm32CodeWriter.prototype.i32_eqz = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_eqz); +}; + +Wasm32CodeWriter.prototype.i32_eq = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_eq); +}; + +Wasm32CodeWriter.prototype.i32_ne = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_ne); +}; + +Wasm32CodeWriter.prototype.i32_add = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_add); +}; + +Wasm32CodeWriter.prototype.i32_sub = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_sub); +}; + +Wasm32CodeWriter.prototype.i32_mul = function() { + this.writeRawBytes(Wasm32CodeWriter.instruction.i32_mul); +}; + +Wasm32CodeWriter.prototype.toUint8Array = function() { + var output = new ResizableUint8Array(); + output.append(VLQEncoder.encodeUInt(this._localTypes.length)); + for (var i = 0; i < this._localTypes.length; ++i) { + output.push(1); + output.push(this._localTypes[i]); + } + output.append(this._data.toUint8Array()); + output.insert_arr(0, VLQEncoder.encodeUInt(output.size())); + return output.toUint8Array(); +}; + +var Wasm32ExportWriter = function(field, kind, index) { + this._field = field; + this._kind = kind; + this._index = index; +}; + +Wasm32ExportWriter.prototype.setName = function(name) { + this._functionname = name; +}; + +Wasm32ExportWriter.prototype.toUint8Array = function() { + var output = new ResizableUint8Array(); + var encoded_field_bytes = encodeUIntString(this._field); + output.append(VLQEncoder.encodeUInt(encoded_field_bytes.length)); + output.append(encoded_field_bytes); + output.push(this._kind); + output.append(VLQEncoder.encodeUInt(this._index)); + return output.toUint8Array(); +}; + +var Wasm32ImportWriter = function(module, field, kind) { + this._module = module; + this._field = field; + this._kind = kind; +}; + +Wasm32ImportWriter.prototype.setName = function(name) { + this._functionname = name; +}; + +Wasm32ImportWriter.prototype.setType = function(type) { + this._functiontype = type; +}; + +Wasm32ImportWriter.prototype.toUint8Array = function() { + var output = new ResizableUint8Array(); + var module_bytes = encodeUIntString(this._module); + var field_bytes = encodeUIntString(this._field); + output.push(VLQEncoder.encodeUInt(module_bytes.length)); + output.append(module_bytes); + output.push(VLQEncoder.encodeUInt(field_bytes.length)); + output.append(field_bytes); + output.push(this._kind); + output.append(VLQEncoder.encodeUInt(this._type)); + return output.toUint8Array(); +}; + +var Wasm32MemoryWriter = function(initial_pages, maximum_pages) { + this._initial_pages = initial_pages; + if (maximum_pages) this._maximum_pages = maximum_pages; +}; + +Wasm32MemoryWriter.prototype.toUint8Array = function() { + var output = new ResizableUint8Array(); + if (this._maximum_pages) { + output.push(1); + output.append(VLQEncoder.encodeUInt(this._initial_pages)); + output.append(VLQEncoder.encodeUInt(this._maximum_pages)); + } else { + output.push(0); + output.append(VLQEncoder.encodeUInt(this._initial_pages)); + } + return output.toUint8Array(); +}; + +var Wasm32ModuleWriter = function() { + this._types = []; + this._imports = []; + this._functions = []; + this._memory = []; + this._exports = []; + this._codes = []; +}; + +Wasm32ModuleWriter.sectionCode = { + TYPE: 1, + IMPORT: 2, + FUNCTION: 3, + TABLE: 4, + MEMORY: 5, + GLOBAL: 6, + EXPORT: 7, + START: 8, + ELEMENT: 9, + CODE: 10, + DATA: 11 +}; + +Wasm32ModuleWriter.prototype.setMemory = function(memory) { + this._memory = [ memory ]; +}; + +Wasm32ModuleWriter.prototype.exportFunction = function(name, field) { + field = field || name; + var exportWriter = new Wasm32ExportWriter(field, Wasm32ExternalKind.function); + exportWriter.setName(name); + this._exports.push(exportWriter); +}; + +Wasm32ModuleWriter.prototype.importFunction = function(name, type, module, field) { + var importWriter = new Wasm32ImportWriter(module, field, Wasm32ExternalKind.function); + importWriter.setName(name); + importWriter.setType(type); + this._imports.push(importWriter); +}; + +Wasm32ModuleWriter.prototype.addFunction = function(name, type, codeWriter) { + codeWriter.setName(name); + codeWriter.setType(type); + this._codes.push(codeWriter); +}; + +Wasm32ModuleWriter.prototype.generateModule = function() { + var funcTypes = []; + var funcTypesOffset = this._types.length; + var funcTypesEqComp = function(type_data) { + return function(el) { + if (el.length != type_data.length) return false; + for (var i = 0; i < el.length; ++i) { + if (el[i] != type_data[i]) return false; + } + return true; + }; + }; + var funcNames = []; + var funcNamesOffset = this._functions.length; + this._imports.forEach(function(obj) { + var name = obj._functionname; + if (name) { + if (funcNames.findIndex(function(el) { + return el.name === name; + }) === -1) funcNames.push({ + name: name, + funcType: obj._functiontype + }); else throw 'Repeated function "' + name + '".'; + } + }); + this._codes.forEach(function(obj) { + var name = obj._functionname; + if (name) { + if (funcNames.findIndex(function(el) { + return el.name === name; + }) === -1) funcNames.push({ + name: name, + funcType: obj._functiontype + }); else throw 'Repeated function "' + name + '".'; + } + }); + funcNames.forEach(function(el) { + if (funcTypes.findIndex(funcTypesEqComp(el.funcType)) === -1) funcTypes.push(el.funcType); + }); + var that = this; + funcTypes.forEach(function(type) { + that._types.push(type); + }); + var that = this; + this._codes.forEach(function(obj) { + var type = obj._functiontype; + if (type) { + var typeIndex = funcTypes.findIndex(funcTypesEqComp(obj._functiontype)) + funcTypesOffset; + if (typeIndex === -1) throw "Weird assembler bug."; + var functionWriter = new Wasm32FunctionWriter(typeIndex); + that._functions.push(functionWriter); + } + }); + this._imports.forEach(function(obj) { + var type = obj._functiontype; + if (type) { + var typeIndex = funcTypes.findIndex(funcTypesEqComp(type)) + funcTypesOffset; + if (typeIndex === -1) throw "Weird assembler bug."; + obj._type = typeIndex; + } + }); + this._codes.forEach(function(obj) { + var functionLinks = obj._functionlinks; + functionLinks.sort(function(a, b) { + return b.location - a.location; + }); + functionLinks.forEach(function(functionLink) { + var funcIndex = funcNames.findIndex(function(el) { + return el.name === functionLink.name; + }) + funcNamesOffset; + if (funcIndex === -1) throw 'Undeclared function "' + functionLink.name + '".'; + obj._data.insert_arr(functionLink.location, VLQEncoder.encodeUInt(funcIndex)); + }); + }); + this._exports.forEach(function(obj) { + var name = obj._functionname; + if (name) { + var funcIndex = funcNames.findIndex(function(el) { + return el.name === name; + }) + funcNamesOffset; + if (funcIndex === -1) throw 'Undeclared function "' + functionLink.name + '".'; + obj._index = funcIndex; + } + }); + this._exports.forEach(function(obj) { + if (obj._functionname) obj._functionname = undefined; + }); + this._imports.forEach(function(obj) { + if (obj._functionname) { + obj._functionname = undefined; + obj._functiontype = undefined; + } + }); + this._codes.forEach(function(obj) { + if (obj._functionname) { + obj._functionname = undefined; + obj._functiontype = undefined; + } + }); + var output = new ResizableUint8Array(); + var wasm_header = new Uint8Array(8); + wasm_header[0] = 0; + wasm_header[1] = 97; + wasm_header[2] = 115; + wasm_header[3] = 109; + wasm_header[4] = 1; + wasm_header[5] = 0; + wasm_header[6] = 0; + wasm_header[7] = 0; + output.append(wasm_header); + if (this._types.length > 0) { + output.push(Wasm32ModuleWriter.sectionCode.TYPE); + var sizeloc = output.size(); + output.append(VLQEncoder.encodeUInt(this._types.length)); + for (var i = 0; i < this._types.length; ++i) { + output.append(this._types[i]); + } + output.insert_arr(sizeloc, VLQEncoder.encodeUInt(output.size() - sizeloc)); + } + if (this._imports.length > 0) { + output.push(Wasm32ModuleWriter.sectionCode.IMPORT); + var sizeloc = output.size(); + output.append(VLQEncoder.encodeUInt(this._imports.length)); + for (var i = 0; i < this._imports.length; ++i) { + output.append(this._imports[i].toUint8Array()); + } + output.insert_arr(sizeloc, VLQEncoder.encodeUInt(output.size() - sizeloc)); + } + if (this._functions.length > 0) { + output.push(Wasm32ModuleWriter.sectionCode.FUNCTION); + var sizeloc = output.size(); + output.append(VLQEncoder.encodeUInt(this._functions.length)); + for (var i = 0; i < this._functions.length; ++i) { + output.append(this._functions[i].toUint8Array()); + } + output.insert_arr(sizeloc, VLQEncoder.encodeUInt(output.size() - sizeloc)); + } + if (this._memory.length > 0) { + output.push(Wasm32ModuleWriter.sectionCode.MEMORY); + var sizeloc = output.size(); + output.append(VLQEncoder.encodeUInt(this._memory.length)); + for (var i = 0; i < this._memory.length; ++i) { + output.append(this._memory[i].toUint8Array()); + } + output.insert_arr(sizeloc, VLQEncoder.encodeUInt(output.size() - sizeloc)); + } + if (this._exports.length > 0) { + output.push(Wasm32ModuleWriter.sectionCode.EXPORT); + var sizeloc = output.size(); + output.append(VLQEncoder.encodeUInt(this._exports.length)); + for (var i = 0; i < this._exports.length; ++i) { + output.append(this._exports[i].toUint8Array()); + } + output.insert_arr(sizeloc, VLQEncoder.encodeUInt(output.size() - sizeloc)); + } + if (this._codes.length > 0) { + output.push(Wasm32ModuleWriter.sectionCode.CODE); + var sizeloc = output.size(); + output.append(VLQEncoder.encodeUInt(this._codes.length)); + for (var i = 0; i < this._codes.length; ++i) { + output.append(this._codes[i].toUint8Array()); + } + output.insert_arr(sizeloc, VLQEncoder.encodeUInt(output.size() - sizeloc)); + } + return output.toUint8Array(); +}; + +var JellyBFCompiler = {}; + +JellyBFCompiler.compile = function(str, options) { + if (options.wraparound === undefined) options.wraparound = true; + if (options.infiniteloops === undefined) options.infiniteloops = true; + if (options.bitwidth === undefined) options.bitwidth = 8; + if (options.bitwidth !== 8 && options.bitwidth !== 16 && options.bitwidth !== 32) return; + var codeChunks = []; + for (var i = 0; i < str.length; ++i) { + switch (str[i]) { + case "+": + var newDelta = new JellyBFRangeDelta(); + newDelta.addDelta(0, 1); + JellyBF_InsertAndAttemptCoalesceDeltas(codeChunks, newDelta); + break; + + case "-": + var newDelta = new JellyBFRangeDelta(); + newDelta.addDelta(0, -1); + JellyBF_InsertAndAttemptCoalesceDeltas(codeChunks, newDelta); + break; + + case ">": + var newDelta = new JellyBFRangeDelta(); + newDelta.addExitDelta(1); + JellyBF_InsertAndAttemptCoalesceDeltas(codeChunks, newDelta); + break; + + case "<": + var newDelta = new JellyBFRangeDelta(); + newDelta.addExitDelta(-1); + JellyBF_InsertAndAttemptCoalesceDeltas(codeChunks, newDelta); + break; + + case "[": + codeChunks.push("["); + break; + + case "]": + JellyBF_CloseAndAttemptUnrollLoop(codeChunks, options); + break; + + case ",": + codeChunks.push(","); + break; + + case ".": + codeChunks.push("."); + break; + } + } + var resolvedCodeChunks = []; + var currentState = new JellyBFPossibleState(true); + for (var i = 0; i < codeChunks.length; ++i) {} + return JellyBF_WriteCodeChunksToModule(codeChunks); +}; + +var JellyBF_WriteCodeChunksToModule = function(codeChunks) { + var moduleWriter = new Wasm32ModuleWriter(); + var memoryWriter = new Wasm32MemoryWriter(16, 16); + moduleWriter.setMemory(memoryWriter); + var codeWriter = new Wasm32CodeWriter([ Wasm32VarType.i32 ]); + codeWriter.i32_const(524288); + codeWriter.set_local(0); + var maxlocals = 1; + for (var i = 0; i < codeChunks.length; ++i) { + if (codeChunks[i] instanceof JellyBFRangeDelta) { + var jellyBFrangedelta = codeChunks[i]; + if (jellyBFrangedelta._data.length > 0) { + var stateRefsLocalOffset = 1; + var stateRefs = []; + jellyBFrangedelta._data.forEach(function(entry) { + if (entry._combination.isZero()) debugger; + entry._combination._terms.forEach(function(term) { + term._parts.forEach(function(part) { + if (part instanceof JellyBFLinearStateRef) { + var stateRefIndex = stateRefs.findIndex(function(arg) { + return arg >= part._index; + }); + if (stateRefIndex === -1) stateRefs.push(part._index); else if (stateRefs[stateRefIndex] !== part._index) stateRefs.splice(stateRefIndex, 0, part._index); + } else debugger; + }); + }); + }); + var offset = Math.min(jellyBFrangedelta._data[0]._index, jellyBFrangedelta._exitindex); + if (stateRefs.length > 0) offset = Math.min(offset, stateRefs[0]); + if (offset !== 0) { + codeWriter.get_local(0); + codeWriter.i32_const(offset); + codeWriter.i32_add(); + codeWriter.set_local(0); + } + stateRefs.forEach(function(ref, localidx) { + var effectiveLocalIdx = stateRefsLocalOffset + localidx; + var effectiveOffset = ref - offset; + codeWriter.get_local(0); + codeWriter.i32_load8_u(effectiveOffset); + codeWriter.set_local(effectiveLocalIdx); + }); + jellyBFrangedelta._data.forEach(function(entry) { + if (entry._combination.isZero()) debugger; + var effectiveOffset = entry._index - offset; + codeWriter.get_local(0); + codeWriter.get_local(0); + codeWriter.i32_load8_u(effectiveOffset); + entry._combination._terms.forEach(function(term, termindex) { + if (term._coefficient === 0) debugger; + if (term._parts.length === 1 && term._coefficient === 1) { + var part = term._parts[0]; + if (part instanceof JellyBFLinearStateRef) { + var stateRefIndex = stateRefs.findIndex(function(arg) { + return arg >= part._index; + }); + var effectiveLocalIdx = stateRefsLocalOffset + stateRefIndex; + codeWriter.get_local(effectiveLocalIdx); + } else debugger; + } else { + codeWriter.i32_const(term._coefficient); + term._parts.forEach(function(part) { + if (part instanceof JellyBFLinearStateRef) { + var stateRefIndex = stateRefs.findIndex(function(arg) { + return arg >= part._index; + }); + var effectiveLocalIdx = stateRefsLocalOffset + stateRefIndex; + codeWriter.get_local(effectiveLocalIdx); + codeWriter.i32_mul(); + } else debugger; + }); + } + codeWriter.i32_add(); + }); + codeWriter.i32_store8(effectiveOffset); + }); + if (jellyBFrangedelta._exitindex - offset !== 0) { + codeWriter.get_local(0); + codeWriter.i32_const(jellyBFrangedelta._exitindex - offset); + codeWriter.i32_add(); + codeWriter.set_local(0); + } + maxlocals = Math.max(maxlocals, stateRefsLocalOffset + stateRefs.length); + } else { + if (jellyBFrangedelta._exitindex !== 0) { + codeWriter.get_local(0); + codeWriter.i32_const(codeChunks[i]._exitindex); + codeWriter.i32_add(); + codeWriter.set_local(0); + } + } + } else { + switch (codeChunks[i]) { + case "[": + codeWriter.get_local(0); + codeWriter.i32_load8_u(0); + codeWriter.if(Wasm32VarType.none); + codeWriter.loop(Wasm32VarType.none); + break; + + case "]": + codeWriter.get_local(0); + codeWriter.i32_load8_u(0); + codeWriter.br_if(0); + codeWriter.end(); + codeWriter.end(); + break; + + case ",": + codeWriter.get_local(0); + codeWriter.call("input"); + codeWriter.i32_store8(0); + break; + + case ".": + codeWriter.get_local(0); + codeWriter.i32_load8_u(0); + codeWriter.call("output"); + break; + } + } + } + codeWriter.end(); + var localTypesParam = []; + for (var i = 0; i < maxlocals; ++i) { + localTypesParam.push(Wasm32VarType.i32); + } + codeWriter.setLocalTypes(localTypesParam); + var type = new Wasm32TypeWriter([], []).toUint8Array(); + moduleWriter.addFunction("main", type, codeWriter); + moduleWriter.exportFunction("main", "main"); + moduleWriter.importFunction("input", new Wasm32TypeWriter([], [ Wasm32VarType.i32 ]).toUint8Array(), "interaction", "input"); + moduleWriter.importFunction("output", new Wasm32TypeWriter([ Wasm32VarType.i32 ], []).toUint8Array(), "interaction", "output"); + var byteCode = moduleWriter.generateModule(); + return byteCode; +}; + +var JellyBFEntry = function(index, delta) { + this._index = index; + this._delta = delta; +}; + +var JellyBFDelta = function() { + this._data = []; + this._exitindex = 0; +}; + +JellyBFDelta.prototype.applyDelta = function(index, delta) { + var dataIndex = this._data.findIndex(function(el) { + return el._index >= index; + }); + if (dataIndex === -1) { + if (delta !== 0) this._data.push(new JellyBFEntry(index, delta)); + } else if (this._data[dataIndex]._index === index) { + this._data[dataIndex]._delta += delta; + if (this._data[dataIndex]._delta === 0) this._data.splice(dataIndex, 1); + } else { + if (delta !== 0) this._data.splice(dataIndex, 0, new JellyBFEntry(index, delta)); + } +}; + +JellyBFDelta.prototype.applyExitDelta = function(delta) { + this._exitindex += delta; +}; + +JellyBFDelta.prototype.coalesceWith = function(jellyBFdelta) { + var that = this; + jellyBFdelta._data.forEach(function(entry) { + that.applyDelta(that._exitindex + entry._index, entry._delta); + }); + this._exitindex += jellyBFdelta._exitindex; +}; + +var find_gcd = function(a, b) { + if (a < b) { + var tmp = a; + a = b; + b = tmp; + } + if (b === 0) return a; + return find_gcd(b, a % b); +}; + +var RationalNumber = function(num, den) { + this._sgn = num < 0; + this._num = Math.abs(num); + this._den = den; +}; + +RationalNumber.prototype.reduce = function() { + var gcd = find_gcd(this._num, this._den); + this._num /= gcd; + this._den /= gcd; +}; + +RationalNumber.prototype.multiplyWith = function(val) { + if (val instanceof RationalNumber) { + this._sgn = this._sgn !== val._sgn; + this._num *= val._num; + this._den *= val._den; + this.reduce(); + } else { + this._sgn = this.sgn !== val < 0; + this.num *= Math.abs(val); + this.reduce(); + } +}; + +var JellyBFLinearStateRef = function(index) { + this._index = index; +}; + +JellyBFLinearStateRef.sortOrder = 1; + +JellyBFLinearStateRef.Comparer = function(a, b) { + return a._index - b._index; +}; + +JellyBFLinearStateRef.prototype.addShift = function(index_shift, input_shift) { + this._index += index_shift; +}; + +JellyBFLinearStateRef.prototype.clone = function() { + return new JellyBFLinearStateRef(this._index); +}; + +var JellyBFLinearInputRef = function(index) { + this._index = index; +}; + +JellyBFLinearInputRef.sortOrder = 2; + +JellyBFLinearInputRef.Comparer = function(a, b) { + return a._index - b._index; +}; + +JellyBFLinearInputRef.prototype.addShift = function(index_shift, input_shift) { + this._index += input_shift; +}; + +JellyBFLinearInputRef.prototype.clone = function() { + return new JellyBFLinearInputRef(this._index); +}; + +var JellyBFLinearTermParts = {}; + +JellyBFLinearTermParts.Comparer = function(a, b) { + var aconstructor = a.constructor; + var bconstructor = b.constructor; + if (aconstructor !== bconstructor) { + return aconstructor.sortOrder - bconstructor.sortOrder; + } + return aconstructor.Comparer(a, b); +}; + +JellyBFLinearTermParts.FinderLow = function(a) { + return function(arg) { + return JellyBFLinearTermParts.Comparer(arg, a) >= 0; + }; +}; + +var JellyBFLinearTerm = function(coefficient) { + this._parts = []; + this._coefficient = coefficient; +}; + +JellyBFLinearTerm.makeConstant = function(value) { + var ret = new JellyBFLinearTerm(); + ret._coefficient = value; + return ret; +}; + +JellyBFLinearTerm.makeFromPart = function(part) { + var ret = new JellyBFLinearTerm(1); + ret._parts = [ part ]; + return ret; +}; + +JellyBFLinearTerm.Comparer = function(a, b) { + var maxlen = Math.max(a._parts.length, b._parts.length); + for (var i = 0; i < maxlen; ++i) { + if (a._parts.length <= i) return -1; + if (b._parts.length <= i) return 1; + var ret = JellyBFLinearTermParts.Comparer(a._parts[i], b._parts[i]); + if (ret !== 0) return ret; + } + return 0; +}; + +JellyBFLinearTerm.FinderLow = function(a) { + return function(arg) { + return JellyBFLinearTerm.Comparer(arg, a) >= 0; + }; +}; + +JellyBFLinearTerm.IsEqual = function(a, b) { + if (a._parts.length !== b._parts.length) return false; + var len = a._parts.length; + for (var i = 0; i < len; ++i) { + var ret = JellyBFLinearTermParts.Comparer(a._parts[i], b._parts[i]); + if (ret !== 0) return false; + } + return true; +}; + +JellyBFLinearTerm.prototype.addWith = function(linearterm) { + this._coefficient += linearterm._coefficient; +}; + +JellyBFLinearTerm.prototype.multiplyWith = function(linearterm) { + if (linearterm.isZero()) debugger; + var this_parts = this._parts; + linearterm._parts.forEach(function(part) { + var index = this_parts.findIndex(JellyBFLinearTermParts.FinderLow(part)); + if (index === -1) { + this_parts.push(part); + } else { + this_parts.splice(index, 0, part); + } + }); + this._coefficient *= linearterm._coefficient; +}; + +JellyBFLinearTerm.prototype.isZero = function() { + return this._coefficient === 0; +}; + +JellyBFLinearTerm.prototype.clone = function() { + var ret = new JellyBFLinearTerm(this._coefficient); + this._parts.forEach(function(part) { + ret._parts.push(part.clone()); + }); + return ret; +}; + +var JellyBFLinear = function() { + this._terms = []; +}; + +JellyBFLinear.prototype.addTerm = function(linearterm) { + if (linearterm.isZero()) debugger; + var dataIndex = this._terms.findIndex(JellyBFLinearTerm.FinderLow(linearterm)); + if (dataIndex === -1) { + this._terms.push(linearterm); + } else if (JellyBFLinearTerm.IsEqual(this._terms[dataIndex], linearterm)) { + this._terms[dataIndex].addWith(linearterm); + if (this._terms[dataIndex].isZero()) this._terms.splice(dataIndex, 1); + } else { + this._terms.splice(dataIndex, 0, linearterm); + } +}; + +JellyBFLinear.prototype.multiplyTerm = function(linearterm) { + if (linearterm.isZero()) debugger; + this._terms.forEach(function(term) { + term.multiplyWith(linearterm.clone()); + }); +}; + +JellyBFLinear.prototype.multiplyLinear = function(linearcombination) { + var old_terms = this._terms; + var new_terms = []; + linearcombination._terms.forEach(function(ins_term) { + old_terms.forEach(function(old_term) { + var cl = old_term.clone(); + cl.multiplyWith(ins_term.clone()); + new_terms.push(cl); + }); + }); + new_terms.sort(JellyBFLinearTerm.Comparer); + this._terms = new_terms; +}; + +JellyBFLinear.prototype.isZero = function() { + return this._terms.length === 0; +}; + +JellyBFLinear.prototype.clone = function() { + var ret = new JellyBFLinear(); + this._terms.forEach(function(term) { + ret._terms.push(term.clone()); + }); + return ret; +}; + +JellyBFLinear.prototype.coalesceWith = function(jellyBFlinear) { + var that = this; + jellyBFlinear._terms.forEach(function(term) { + that.addTerm(term); + }); +}; + +JellyBFLinear.prototype.expandState = function(jellyBFrangedelta) { + if (!(jellyBFrangedelta instanceof JellyBFRangeDelta)) debugger; + var new_terms = []; + this._terms.forEach(function(term) { + var part_indices_for_expansion = []; + var new_term = new JellyBFLinearTerm(term._coefficient); + term._parts.forEach(function(part) { + if (part instanceof JellyBFLinearStateRef) { + part_indices_for_expansion.push(part._index); + } else if (part instanceof JellyBFLinearOutputRef) { + new_term.push(part); + } else debugger; + }); + var lincombin = new JellyBFLinear(); + lincombin.addTerm(JellyBFLinearTerm.makeConstant(1)); + part_indices_for_expansion.forEach(function(index) { + var applyIndex = jellyBFrangedelta._data.findIndex(JellyBFRangeEntry.FinderEqualIndex(index)); + var applyCombination = new JellyBFLinear(); + applyCombination.addTerm(JellyBFLinearTerm.makeFromPart(new JellyBFLinearStateRef(index))); + if (applyIndex !== -1) { + applyCombination.coalesceWith(jellyBFrangedelta._data[applyIndex]._combination.clone()); + } + lincombin.multiplyLinear(applyCombination); + }); + lincombin.multiplyTerm(new_term); + lincombin._terms.forEach(function(term) { + new_terms.push(term); + }); + }); + this._terms = []; + var that = this; + new_terms.forEach(function(term) { + that.addTerm(term); + }); +}; + +JellyBFLinear.IsExactSame = function(a, b) { + if (a._terms.length !== b._terms.length) return false; + var maxlen = a._terms.length; + for (var i = 0; i < maxlen; ++i) { + if (!JellyBFLinearTerm.IsEqual(a._terms[i], b._terms[i])) return false; + if (a._terms[i]._coefficient !== b._terms[i]._coefficient) return false; + } + return true; +}; + +var JellyBFRangeEntry = function(index) { + this._index = index; + this._combination = new JellyBFLinear(); +}; + +JellyBFRangeEntry.Comparer = function(a, b) { + return a._index - b._index; +}; + +JellyBFRangeEntry.FinderLow = function(a) { + return function(arg) { + return arg._index >= a._index; + }; +}; + +JellyBFRangeEntry.FinderLowIndex = function(index) { + return function(arg) { + return arg._index >= index; + }; +}; + +JellyBFRangeEntry.FinderEqual = function(a) { + return function(arg) { + return arg._index === a._index; + }; +}; + +JellyBFRangeEntry.FinderEqualIndex = function(index) { + return function(arg) { + return arg._index === index; + }; +}; + +JellyBFRangeEntry.IsEqual = function(a, b) { + return a._index === b._index; +}; + +JellyBFRangeEntry.IsEqualIndex = function(a, index) { + return a._index === index; +}; + +JellyBFRangeEntry.prototype.addTerm = function(linearterm) { + this._combination.addTerm(linearterm); +}; + +JellyBFRangeEntry.prototype.multiplyTerm = function(linearterm) { + this._combination.multiplyTerm(linearterm); +}; + +JellyBFRangeEntry.prototype.isZero = function() { + return this._combination.isZero(); +}; + +JellyBFRangeEntry.prototype.coalesceWith = function(jellyBFrangeentry) { + this._combination.coalesceWith(jellyBFrangeentry._combination); +}; + +JellyBFRangeEntry.makeFromTerm = function(index, term) { + if (!(term instanceof JellyBFLinearTerm)) debugger; + var ret = new JellyBFRangeEntry(index); + ret.addTerm(term); + return ret; +}; + +var JellyBFRangeDelta = function() { + this._data = []; + this._outputs = []; + this._exitindex = 0; + this._inputcount = 0; +}; + +JellyBFRangeDelta.prototype.addEntry = function(jellyBFrangeentry) { + var dataIndex = this._data.findIndex(JellyBFRangeEntry.FinderLow(jellyBFrangeentry)); + if (dataIndex === -1) { + this._data.push(jellyBFrangeentry); + } else if (JellyBFRangeEntry.IsEqual(this._data[dataIndex], jellyBFrangeentry)) { + this._data[dataIndex].coalesceWith(jellyBFrangeentry); + if (this._data[dataIndex].isZero()) this._data.splice(dataIndex, 1); + } else { + this._data.splice(dataIndex, 0, jellyBFrangeentry); + } +}; + +JellyBFRangeDelta.prototype.addDelta = function(index, delta) { + var dataIndex = this._data.findIndex(JellyBFRangeEntry.FinderLowIndex(index)); + if (dataIndex === -1) { + if (delta !== 0) this._data.push(JellyBFRangeEntry.makeFromTerm(index, JellyBFLinearTerm.makeConstant(delta))); + } else if (JellyBFRangeEntry.IsEqualIndex(this._data[dataIndex], index)) { + this._data[dataIndex].addTerm(JellyBFLinearTerm.makeConstant(delta)); + if (this._data[dataIndex].isZero()) this._data.splice(dataIndex, 1); + } else { + if (delta !== 0) this._data.splice(dataIndex, 0, JellyBFRangeEntry.makeFromTerm(index, JellyBFLinearTerm.makeConstant(delta))); + } +}; + +JellyBFRangeDelta.prototype.addExitDelta = function(delta) { + this._exitindex += delta; +}; + +JellyBFRangeDelta.prototype.coalesceWith = function(jellyBFrangedelta) { + var that = this; + var exitindex_offset = this._exitindex; + var inputindex_offset = this._inputcount; + jellyBFrangedelta._data.forEach(function(rangeentry) { + rangeentry._index += exitindex_offset; + rangeentry._combination._terms.forEach(function(linearterm) { + linearterm._parts.forEach(function(linearpart) { + linearpart.addShift(exitindex_offset, inputindex_offset); + }); + }); + }); + jellyBFrangedelta._outputs.forEach(function(linearcombination) { + linearcombination._terms.forEach(function(linearterm) { + linearterm._parts.forEach(function(linearpart) { + linearpart.addShift(exitindex_offset, inputindex_offset); + }); + }); + }); + var entries_to_add = []; + jellyBFrangedelta._data.forEach(function(entry) { + entry._combination.expandState(that); + entries_to_add.push(entry); + }); + jellyBFrangedelta._outputs.forEach(function(linearcombination) { + linearcombination.expandState(that); + that._outputs.push(linearcombination); + }); + entries_to_add.forEach(function(entry) { + that.addEntry(entry); + }); + for (var i = this._data.length - 1; i >= 0; --i) { + if (this._data[i].isZero()) this._data.splice(i, 1); + } + this._exitindex += jellyBFrangedelta._exitindex; + this._inputcount += jellyBFrangedelta._inputcount; +}; + +JellyBFRangeDelta.prototype.wrapWithLoop = function(options) { + if (this._exitindex === 0) { + var dataIndex = this._data.findIndex(JellyBFRangeEntry.FinderEqualIndex(0)); + if (dataIndex === -1) { + return false; + } else if (JellyBFLinear.IsExactSame(this._data[dataIndex]._combination, JellyBFRangeEntry.makeFromTerm(0, JellyBFLinearTerm.makeConstant(-1))._combination)) { + var is_all_constant = true; + this._data.forEach(function(jellybfentry) { + jellybfentry._combination._terms.forEach(function(term) { + if (term._parts.length !== 0) is_all_constant = false; + }); + }); + if (!is_all_constant) return false; + this._data.forEach(function(jellybfentry) { + var newTerm = new JellyBFLinearTerm(1); + newTerm._parts.push(new JellyBFLinearStateRef(0)); + jellybfentry.multiplyTerm(newTerm); + }); + return true; + } + return false; + } + return false; +}; + +JellyBFRangeDelta.prototype.writeCode = function(codeWriter) {}; + +var JellyBFPossibleStateEntry = function(index, value) { + this._index = index; + this._value = value; +}; + +JellyBFPossibleStateEntry.FinderLowIndex = function(index) { + return function(arg) { + return arg._index >= index; + }; +}; + +var JellyBFPossibleState = function(emptyIsZero) { + if (emptyIsZero !== true && emptyIsZero !== false) debugger; + this.emptyIsZero = emptyIsZero; + this._data = []; +}; + +JellyBFPossibleState.prototype.getState = function(index) { + var dataIndex = this._data.findIndex(JellyBFPossibleStateEntry.FinderLowIndex(index)); + if (dataIndex === -1) { + if (this.emptyIsZero) { + return 0; + } else { + return undefined; + } + } + return this._data[dataIndex]._value; +}; + +JellyBFPossibleState.prototype.setState = function(index, value) { + var dataIndex = this._data.findIndex(JellyBFPossibleStateEntry.FinderLowIndex(index)); + if (dataIndex === -1) { + if (this.emptyIsZero && value !== 0 || !this.emptyIsZero && value !== undefined) { + this._data.splice(dataIndex, 0, new JellyBFPossibleStateEntry(index, value)); + } + } else { + if (this.emptyIsZero && value === 0 || !this.emptyIsZero && value === undefined) { + this._data.splice(dataIndex, 1); + } else { + this._data[dataIndex]._value = value; + } + } +}; + +var JellyBF_InsertAndAttemptCoalesceDeltas = function(codeChunks, newDelta) { + if (codeChunks.length > 0 && codeChunks[codeChunks.length - 1] instanceof JellyBFRangeDelta) { + codeChunks[codeChunks.length - 1].coalesceWith(newDelta); + } else { + codeChunks.push(newDelta); + } +}; + +var JellyBF_CloseAndAttemptUnrollLoop = function(codeChunks, options) { + if (codeChunks.length > 0 && codeChunks[codeChunks.length - 1] === "[") { + if (options.infiniteloops) { + codeChunks.push("]"); + } else { + codeChunks.pop(); + } + } else if (codeChunks.length > 1 && codeChunks[codeChunks.length - 1] instanceof JellyBFRangeDelta && codeChunks[codeChunks.length - 2] === "[") { + var chunk = codeChunks.pop(); + if (chunk.wrapWithLoop(options)) { + codeChunks.pop(); + JellyBF_InsertAndAttemptCoalesceDeltas(codeChunks, chunk); + } else { + codeChunks.push(chunk); + codeChunks.push("]"); + } + } else { + codeChunks.push("]"); + } +}; + +var JellyBFSync = { + compile: function(str, options) { + return WebAssembly.Module(JellyBFCompiler.compile(str, options)); + }, + execute: function(module, inputuint8array, options) { + options.eof_value = options.eof_value || 0; + var inputindex = 0; + var outputdata = new ResizableUint8Array(); + var get_input = function() { + if (inputindex < inputuint8array.length) { + return inputuint8array[inputindex++]; + } else { + return options.eof_value; + } + }; + var put_output = function(byte) { + outputdata.push(byte); + }; + var instance = WebAssembly.Instance(module, { + interaction: { + input: get_input, + output: put_output + } + }); + instance.exports.main(); + return outputdata.toUint8Array(); + }, + executeInteractive: function(module, inputuint8array, outputuint8array, inputwaitint32array, outputwaitint32array, options) { + var WaitArrayId = { + READ_HEAD: 0, + WRITE_HEAD: 1, + TERMINATED_FLAG: 2 + }; + options.bufferlength = options.bufferlength || 1024; + options.eof_value = options.eof_value || 0; + var input_read_head = 0, input_write_head = 0, input_terminated = false; + var get_input = function() { + if (input_read_head === input_write_head) { + Atomics.wait(inputwaitint32array, WaitArrayId.WRITE_HEAD, input_write_head); + input_write_head = Atomics.load(inputwaitint32array, WaitArrayId.WRITE_HEAD); + if (!input_terminated) { + input_terminated = Atomics.load(inputwaitint32array, WaitArrayId.TERMINATED_FLAG) !== 0; + } + } + if (!input_terminated || input_read_head + 1 < input_write_head) { + var val = Atomics.load(inputuint8array, input_read_head++ % options.bufferlength); + Atomics.store(inputwaitint32array, WaitArrayId.READ_HEAD, input_read_head); + return val; + } else { + return options.eof_value; + } + }; + var output_read_head = 0, output_write_head = 0, output_terminated = false; + var put_output = function(byte) { + if (output_read_head + options.bufferlength === output_write_head) { + Atomics.wait(outputwaitint32array, WaitArrayId.READ_HEAD, output_read_head); + output_read_head = Atomics.load(outputwaitint32array, WaitArrayId.READ_HEAD); + } + Atomics.store(outputuint8array, output_write_head++ % options.bufferlength, byte); + Atomics.store(outputwaitint32array, WaitArrayId.WRITE_HEAD, output_write_head); + }; + var terminate_output = function() { + if (output_read_head + options.bufferlength === output_write_head) { + Atomics.wait(outputwaitint32array, WaitArrayId.READ_HEAD, output_read_head); + output_read_head = Atomics.load(outputwaitint32array, WaitArrayId.READ_HEAD); + } + Atomics.store(outputwaitint32array, WaitArrayId.TERMINATED_FLAG, 1); + Atomics.store(outputwaitint32array, WaitArrayId.WRITE_HEAD, output_write_head + 1); + }; + var instance = WebAssembly.Instance(module, { + interaction: { + input: get_input, + output: put_output + } + }); + instance.exports.main(); + terminate_output(); + return true; + } +}; + +(function() { + var module = undefined; + self.addEventListener("message", function(e) { + var message = e.data; + switch (message.type) { + case "compile": + var sourcecode = message.sourcecode; + var options = message.options; + module = JellyBFSync.compile(sourcecode, options); + self.postMessage({ + type: "compiled" + }); + break; + + case "execute-interactive": + var inputbuffer = message.inputbuffer; + var outputbuffer = message.outputbuffer; + var inputwaitbuffer = message.inputwaitbuffer; + var outputwaitbuffer = message.outputwaitbuffer; + var options = message.options; + JellyBFSync.executeInteractive(module, UInt8Array(inputbuffer), UInt8Array(outputbuffer), Int32Array(inputwaitbuffer), Int32Array(outputwaitbuffer), options); + self.postMessage({ + type: "executed" + }); + break; + + case "execute": + var inputuint8array = message.inputuint8array; + var options = message.options; + var outputuint8array = JellyBFSync.execute(module, inputuint8array, options); + self.postMessage({ + type: "executed", + outputuint8array: outputuint8array + }, [ outputuint8array.buffer ]); + break; + } + }); + self.postMessage({ + type: "ready" + }); +})(); \ No newline at end of file diff --git a/jelly-bf-worker.min.js b/jelly-bf-worker.min.js new file mode 100644 index 0000000..9d9fe5c --- /dev/null +++ b/jelly-bf-worker.min.js @@ -0,0 +1 @@ +var t=function(){this._buffer=new ArrayBuffer(8),this._data=new Uint8Array(this._buffer),this._size=0};t.prototype.size=function(){return this._size},t.prototype.get=function(t){return this._data[t]},t.prototype.set=function(t,n){this._data[t]=n},t.prototype.reserve_extra=function(t){if(this._size+t>this._data.length){for(var n=new ArrayBuffer(Math.max(2*this._data.length,this._size+t)),e=new Uint8Array(n),i=0;this._size>i;++i)e[i]=this._data[i];this._buffer=n,this._data=e}},t.prototype.push=function(t){this.reserve_extra(1),this._data[this._size++]=t},t.prototype.append=function(t){this.reserve_extra(t.length);for(var n=0;t.length>n;++n)this._data[this._size++]=t[n]},t.prototype.pop=function(){return this._data[--this._size]},t.prototype.insert_arr=function(t,n){this.reserve_extra(n.length);for(var e=this._size-1;e>=t;--e)this._data[e+n.length]=this._data[e];for(var e=0;n.length>e;++e)this._data[t+e]=n[e];this._size+=n.length},t.prototype.toUint8Array=function(){for(var t=new Uint8Array(this._size),n=0;this._size>n;++n)t[n]=this._data[n];return t};var n=function(t){return(new TextEncoder).encode(t)},e={};e.encodeUInt=function(n){0>n||n!==Math.floor(n);for(var e=new t;;){var i=n%128;if(n=Math.floor(n/128),0>=n){e.push(i);break}e.push(128+i)}return e.toUint8Array()},e.encodeInt=function(n){n!==Math.floor(n);var e=new t,i=0>n;for(i&&(n=-n-1);;){var r=n%128;if(n=Math.floor(n/128),0>=n&&64>r){e.push(i?127&~r:r);break}e.push(i?255&~r:128+r)}return e.toUint8Array()};var i={i32:127,i64:126,f32:125,f64:124,anyfunc:112,func:96,none:64},r={function:0,table:1,memory:2,global:3},o=function(t,n){this._param_types=t?t:[],this._result_types=n?n:[]};o.prototype.toUint8Array=function(){var n=new t;n.push(i.func),n.append(e.encodeUInt(this._param_types.length));for(var r=0;this._param_types.length>r;++r)n.push(this._param_types[r]);n.append(e.encodeUInt(this._result_types.length));for(var r=0;this._result_types.length>r;++r)n.push(this._result_types[r]);return n.toUint8Array()};var s=function(t){this._type=t};s.prototype.toUint8Array=function(){var n=new t;return n.append(e.encodeUInt(this._type)),n.toUint8Array()};var a=function(n){this._localTypes=n?n:[],this._data=new t,this._functionlinks=[]};a.prototype.setName=function(t){this._functionname=t},a.prototype.setType=function(t){this._functiontype=t},a.prototype.setLocalTypes=function(t){this._localTypes=t?t:[]},a.instruction={unreachable:0,nop:1,block:2,loop:3,if:4,else:5,end:11,br:12,br_if:13,br_table:14,return:15,call:16,call_indirect:17,drop:26,select:27,get_local:32,set_local:33,tee_local:34,get_global:35,set_global:36,i32_load:40,i64_load:41,f32_load:42,f64_load:43,i32_load8_s:44,i32_load8_u:45,i32_load16_s:46,i32_load16_u:47,i64_load8_s:48,i64_load8_u:49,i64_load16_s:50,i64_load16_u:51,i64_load32_s:52,i64_load32_u:53,i32_store:54,i64_store:55,f32_store:56,f64_store:57,i32_store8:58,i32_store16:59,i64_store8:60,i64_store16:61,i64_store32:62,current_memory:63,grow_memory:64,i32_const:65,i64_const:66,f32_const:67,f64_const:68,i32_eqz:69,i32_eq:70,i32_ne:71,i32_add:106,i32_sub:107,i32_mul:108},a.prototype.writeRawBytes=function(){for(var t=0;arguments.length>t;++t)this._data.push(arguments[t])},a.prototype.writeUint8Array=function(t){this._data.append(t)},a.prototype.unreachable=function(){this.writeRawBytes(a.instruction.unreachable)},a.prototype.nop=function(){this.writeRawBytes(a.instruction.nop)},a.prototype.block=function(t){this.writeRawBytes(a.instruction.block,t)},a.prototype.loop=function(t){this.writeRawBytes(a.instruction.loop,t)},a.prototype.if=function(t){this.writeRawBytes(a.instruction.if,t)},a.prototype.else=function(){this.writeRawBytes(a.instruction.else)},a.prototype.end=function(){this.writeRawBytes(a.instruction.end)},a.prototype.br=function(t){this.writeRawBytes(a.instruction.br),this.writeUint8Array(e.encodeUInt(t))},a.prototype.br_if=function(t){this.writeRawBytes(a.instruction.br_if),this.writeUint8Array(e.encodeUInt(t))},a.prototype.return=function(){this.writeRawBytes(a.instruction.return)},a.prototype.call=function(t){"number"==typeof t?(this.writeRawBytes(a.instruction.call),this.writeUint8Array(e.encodeUInt(t))):(this.writeRawBytes(a.instruction.call),this._functionlinks.push({location:this._data.size(),name:t}))},a.prototype.drop=function(){this.writeRawBytes(a.instruction.drop)},a.prototype.select=function(){this.writeRawBytes(a.instruction.select)},a.prototype.get_local=function(t){this.writeRawBytes(a.instruction.get_local),this.writeUint8Array(e.encodeUInt(t))},a.prototype.set_local=function(t){this.writeRawBytes(a.instruction.set_local),this.writeUint8Array(e.encodeUInt(t))},a.prototype.tee_local=function(t){this.writeRawBytes(a.instruction.tee_local),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_load=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_load),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.f32_load=function(t,n){n=n||0,this.writeRawBytes(a.instruction.f32_load),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.f64_load=function(t,n){n=n||0,this.writeRawBytes(a.instruction.f64_load),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_load8_s=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_load8_s),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_load8_u=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_load8_u),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_load16_s=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_load16_s),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_load16_u=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_load16_u),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load8_s=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load8_s),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load8_u=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load8_u),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load16_s=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load16_s),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load16_u=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load16_u),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load32_s=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load32_s),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_load32_u=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_load32_u),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_store=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_store),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_store=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_store),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.f32_store=function(t,n){n=n||0,this.writeRawBytes(a.instruction.f32_store),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.f64_store=function(t,n){n=n||0,this.writeRawBytes(a.instruction.f64_store),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_store8=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_store8),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i32_store16=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i32_store16),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_store8=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_store8),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_store16=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_store16),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.i64_store32=function(t,n){n=n||0,this.writeRawBytes(a.instruction.i64_store32),this.writeUint8Array(e.encodeUInt(n)),this.writeUint8Array(e.encodeUInt(t))},a.prototype.current_memory=function(){this.writeRawBytes(a.instruction.current_memory,0)},a.prototype.grow_memory=function(){this.writeRawBytes(a.instruction.grow_memory,0)},a.prototype.i32_const=function(t){this.writeRawBytes(a.instruction.i32_const),this.writeUint8Array(e.encodeInt(t))},a.prototype.i64_const=function(t){this.writeRawBytes(a.instruction.i64_const),this.writeUint8Array(e.encodeInt(t))},a.prototype.i32_eqz=function(){this.writeRawBytes(a.instruction.i32_eqz)},a.prototype.i32_eq=function(){this.writeRawBytes(a.instruction.i32_eq)},a.prototype.i32_ne=function(){this.writeRawBytes(a.instruction.i32_ne)},a.prototype.i32_add=function(){this.writeRawBytes(a.instruction.i32_add)},a.prototype.i32_sub=function(){this.writeRawBytes(a.instruction.i32_sub)},a.prototype.i32_mul=function(){this.writeRawBytes(a.instruction.i32_mul)},a.prototype.toUint8Array=function(){var n=new t;n.append(e.encodeUInt(this._localTypes.length));for(var i=0;this._localTypes.length>i;++i)n.push(1),n.push(this._localTypes[i]);return n.append(this._data.toUint8Array()),n.insert_arr(0,e.encodeUInt(n.size())),n.toUint8Array()};var c=function(t,n,e){this._field=t,this._kind=n,this._index=e};c.prototype.setName=function(t){this._functionname=t},c.prototype.toUint8Array=function(){var i=new t,r=n(this._field);return i.append(e.encodeUInt(r.length)),i.append(r),i.push(this._kind),i.append(e.encodeUInt(this._index)),i.toUint8Array()};var u=function(t,n,e){this._module=t,this._field=n,this._kind=e};u.prototype.setName=function(t){this._functionname=t},u.prototype.setType=function(t){this._functiontype=t},u.prototype.toUint8Array=function(){var i=new t,r=n(this._module),o=n(this._field);return i.push(e.encodeUInt(r.length)),i.append(r),i.push(e.encodeUInt(o.length)),i.append(o),i.push(this._kind),i.append(e.encodeUInt(this._type)),i.toUint8Array()};var _=function(t,n){this._initial_pages=t,n&&(this._maximum_pages=n)};_.prototype.toUint8Array=function(){var n=new t;return this._maximum_pages?(n.push(1),n.append(e.encodeUInt(this._initial_pages)),n.append(e.encodeUInt(this._maximum_pages))):(n.push(0),n.append(e.encodeUInt(this._initial_pages))),n.toUint8Array()};var h=function(){this._types=[],this._imports=[],this._functions=[],this._memory=[],this._exports=[],this._codes=[]};h.sectionCode={TYPE:1,IMPORT:2,FUNCTION:3,TABLE:4,MEMORY:5,GLOBAL:6,EXPORT:7,START:8,ELEMENT:9,CODE:10,DATA:11},h.prototype.setMemory=function(t){this._memory=[t]},h.prototype.exportFunction=function(t,n){n=n||t;var e=new c(n,r.function);e.setName(t),this._exports.push(e)},h.prototype.importFunction=function(t,n,e,i){var o=new u(e,i,r.function);o.setName(t),o.setType(n),this._imports.push(o)},h.prototype.addFunction=function(t,n,e){e.setName(t),e.setType(n),this._codes.push(e)},h.prototype.generateModule=function(){var n=[],i=this._types.length,r=function(t){return function(n){if(n.length!=t.length)return!1;for(var e=0;n.length>e;++e)if(n[e]!=t[e])return!1;return!0}},o=[],a=this._functions.length;this._imports.forEach(function(t){var n=t._functionname;if(n){if(o.findIndex(function(t){return t.name===n})!==-1)throw'Repeated function "'+n+'".';o.push({name:n,funcType:t._functiontype})}}),this._codes.forEach(function(t){var n=t._functionname;if(n){if(o.findIndex(function(t){return t.name===n})!==-1)throw'Repeated function "'+n+'".';o.push({name:n,funcType:t._functiontype})}}),o.forEach(function(t){n.findIndex(r(t.funcType))===-1&&n.push(t.funcType)});var c=this;n.forEach(function(t){c._types.push(t)});var c=this;this._codes.forEach(function(t){if(t._functiontype){var e=n.findIndex(r(t._functiontype))+i;if(e===-1)throw"Weird assembler bug.";c._functions.push(new s(e))}}),this._imports.forEach(function(t){var e=t._functiontype;if(e){var o=n.findIndex(r(e))+i;if(o===-1)throw"Weird assembler bug.";t._type=o}}),this._codes.forEach(function(t){var n=t._functionlinks;n.sort(function(t,n){return n.location-t.location}),n.forEach(function(n){var i=o.findIndex(function(t){return t.name===n.name})+a;if(i===-1)throw'Undeclared function "'+n.name+'".';t._data.insert_arr(n.location,e.encodeUInt(i))})}),this._exports.forEach(function(t){var n=t._functionname;if(n){var e=o.findIndex(function(t){return t.name===n})+a;if(e===-1)throw'Undeclared function "'+functionLink.name+'".';t._index=e}}),this._exports.forEach(function(t){t._functionname&&(t._functionname=void 0)}),this._imports.forEach(function(t){t._functionname&&(t._functionname=void 0,t._functiontype=void 0)}),this._codes.forEach(function(t){t._functionname&&(t._functionname=void 0,t._functiontype=void 0)});var u=new t,_=new Uint8Array(8);if(_[0]=0,_[1]=97,_[2]=115,_[3]=109,_[4]=1,_[5]=0,_[6]=0,_[7]=0,u.append(_),this._types.length>0){u.push(h.sectionCode.TYPE);var p=u.size();u.append(e.encodeUInt(this._types.length));for(var f=0;this._types.length>f;++f)u.append(this._types[f]);u.insert_arr(p,e.encodeUInt(u.size()-p))}if(this._imports.length>0){u.push(h.sectionCode.IMPORT);var p=u.size();u.append(e.encodeUInt(this._imports.length));for(var f=0;this._imports.length>f;++f)u.append(this._imports[f].toUint8Array());u.insert_arr(p,e.encodeUInt(u.size()-p))}if(this._functions.length>0){u.push(h.sectionCode.FUNCTION);var p=u.size();u.append(e.encodeUInt(this._functions.length));for(var f=0;this._functions.length>f;++f)u.append(this._functions[f].toUint8Array());u.insert_arr(p,e.encodeUInt(u.size()-p))}if(this._memory.length>0){u.push(h.sectionCode.MEMORY);var p=u.size();u.append(e.encodeUInt(this._memory.length));for(var f=0;this._memory.length>f;++f)u.append(this._memory[f].toUint8Array());u.insert_arr(p,e.encodeUInt(u.size()-p))}if(this._exports.length>0){u.push(h.sectionCode.EXPORT);var p=u.size();u.append(e.encodeUInt(this._exports.length));for(var f=0;this._exports.length>f;++f)u.append(this._exports[f].toUint8Array());u.insert_arr(p,e.encodeUInt(u.size()-p))}if(this._codes.length>0){u.push(h.sectionCode.CODE);var p=u.size();u.append(e.encodeUInt(this._codes.length));for(var f=0;this._codes.length>f;++f)u.append(this._codes[f].toUint8Array());u.insert_arr(p,e.encodeUInt(u.size()-p))}return u.toUint8Array()};var p={};p.compile=function(t,n){if(void 0===n.wraparound&&(n.wraparound=!0),void 0===n.infiniteloops&&(n.infiniteloops=!0),void 0===n.bitwidth&&(n.bitwidth=8),8===n.bitwidth||16===n.bitwidth||32===n.bitwidth){for(var e=[],i=0;t.length>i;++i)switch(t[i]){case"+":var r=new g;r.addDelta(0,1),R(e,r);break;case"-":var r=new g;r.addDelta(0,-1),R(e,r);break;case">":var r=new g;r.addExitDelta(1),R(e,r);break;case"<":var r=new g;r.addExitDelta(-1),R(e,r);break;case"[":e.push("[");break;case"]":T(e,n);break;case",":e.push(",");break;case".":e.push(".")}for(var i=(new b(!0),0);e.length>i;++i);return f(e)}};var f=function(t){var n=new h;n.setMemory(new _(16,16));var e=new a([i.i32]);e.i32_const(524288),e.set_local(0);for(var r=1,s=0;t.length>s;++s)if(t[s]instanceof g){var c=t[s];if(c._data.length>0){var u=1,p=[];c._data.forEach(function(t){t._combination.isZero(),t._combination._terms.forEach(function(t){t._parts.forEach(function(t){if(t instanceof w){var n=p.findIndex(function(n){return n>=t._index});n===-1?p.push(t._index):p[n]!==t._index&&p.splice(n,0,t._index)}})})});var f=Math.min(c._data[0]._index,c._exitindex);p.length>0&&(f=Math.min(f,p[0])),0!==f&&(e.get_local(0),e.i32_const(f),e.i32_add(),e.set_local(0)),p.forEach(function(t,n){var i=u+n,r=t-f;e.get_local(0),e.i32_load8_u(r),e.set_local(i)}),c._data.forEach(function(t){t._combination.isZero();var n=t._index-f;e.get_local(0),e.get_local(0),e.i32_load8_u(n),t._combination._terms.forEach(function(t){if(1===t._parts.length&&1===t._coefficient){var n=t._parts[0];n instanceof w&&e.get_local(u+p.findIndex(function(t){return t>=n._index}))}else e.i32_const(t._coefficient),t._parts.forEach(function(t){t instanceof w&&(e.get_local(u+p.findIndex(function(n){return n>=t._index})),e.i32_mul())});e.i32_add()}),e.i32_store8(n)}),c._exitindex-f!==0&&(e.get_local(0),e.i32_const(c._exitindex-f),e.i32_add(),e.set_local(0)),r=Math.max(r,u+p.length)}else 0!==c._exitindex&&(e.get_local(0),e.i32_const(t[s]._exitindex),e.i32_add(),e.set_local(0))}else switch(t[s]){case"[":e.get_local(0),e.i32_load8_u(0),e.if(i.none),e.loop(i.none);break;case"]":e.get_local(0),e.i32_load8_u(0),e.br_if(0),e.end(),e.end();break;case",":e.get_local(0),e.call("input"),e.i32_store8(0);break;case".":e.get_local(0),e.i32_load8_u(0),e.call("output")}e.end();for(var d=[],s=0;r>s;++s)d.push(i.i32);return e.setLocalTypes(d),n.addFunction("main",new o([],[]).toUint8Array(),e),n.exportFunction("main","main"),n.importFunction("input",new o([],[i.i32]).toUint8Array(),"interaction","input"),n.importFunction("output",new o([i.i32],[]).toUint8Array(),"interaction","output"),n.generateModule()},d=function(t,n){this._index=t,this._delta=n},l=function(){this._data=[],this._exitindex=0};l.prototype.applyDelta=function(t,n){var e=this._data.findIndex(function(n){return n._index>=t});e===-1?0!==n&&this._data.push(new d(t,n)):this._data[e]._index===t?(this._data[e]._delta+=n,0===this._data[e]._delta&&this._data.splice(e,1)):0!==n&&this._data.splice(e,0,new d(t,n))},l.prototype.applyExitDelta=function(t){this._exitindex+=t},l.prototype.coalesceWith=function(t){var n=this;t._data.forEach(function(t){n.applyDelta(n._exitindex+t._index,t._delta)}),this._exitindex+=t._exitindex};var y=function(t,n){if(n>t){var e=t;t=n,n=e}return 0===n?t:y(n,t%n)},m=function(t,n){this._sgn=0>t,this._num=Math.abs(t),this._den=n};m.prototype.reduce=function(){var t=y(this._num,this._den);this._num/=t,this._den/=t},m.prototype.multiplyWith=function(t){t instanceof m?(this._sgn=this._sgn!==t._sgn,this._num*=t._num,this._den*=t._den,this.reduce()):(this._sgn=this.sgn!==0>t,this.num*=Math.abs(t),this.reduce())};var w=function(t){this._index=t};w.sortOrder=1,w.Comparer=function(t,n){return t._index-n._index},w.prototype.addShift=function(t){this._index+=t},w.prototype.clone=function(){return new w(this._index)};var U=function(t){this._index=t};U.sortOrder=2,U.Comparer=function(t,n){return t._index-n._index},U.prototype.addShift=function(t,n){this._index+=n},U.prototype.clone=function(){return new U(this._index)};var v={};v.Comparer=function(t,n){var e=t.constructor,i=n.constructor;return e!==i?e.sortOrder-i.sortOrder:e.Comparer(t,n)},v.FinderLow=function(t){return function(n){return v.Comparer(n,t)>=0}};var I=function(t){this._parts=[],this._coefficient=t};I.makeConstant=function(t){var n=new I;return n._coefficient=t,n},I.makeFromPart=function(t){var n=new I(1);return n._parts=[t],n},I.Comparer=function(t,n){for(var e=Math.max(t._parts.length,n._parts.length),i=0;e>i;++i){if(i>=t._parts.length)return-1;if(i>=n._parts.length)return 1;var r=v.Comparer(t._parts[i],n._parts[i]);if(0!==r)return r}return 0},I.FinderLow=function(t){return function(n){return I.Comparer(n,t)>=0}},I.IsEqual=function(t,n){if(t._parts.length!==n._parts.length)return!1;for(var e=t._parts.length,i=0;e>i;++i)if(0!==v.Comparer(t._parts[i],n._parts[i]))return!1;return!0},I.prototype.addWith=function(t){this._coefficient+=t._coefficient},I.prototype.multiplyWith=function(t){t.isZero();var n=this._parts;t._parts.forEach(function(t){var e=n.findIndex(v.FinderLow(t));e===-1?n.push(t):n.splice(e,0,t)}),this._coefficient*=t._coefficient},I.prototype.isZero=function(){return 0===this._coefficient},I.prototype.clone=function(){var t=new I(this._coefficient);return this._parts.forEach(function(n){t._parts.push(n.clone())}),t};var x=function(){this._terms=[]};x.prototype.addTerm=function(t){t.isZero();var n=this._terms.findIndex(I.FinderLow(t));n===-1?this._terms.push(t):I.IsEqual(this._terms[n],t)?(this._terms[n].addWith(t),this._terms[n].isZero()&&this._terms.splice(n,1)):this._terms.splice(n,0,t)},x.prototype.multiplyTerm=function(t){t.isZero(),this._terms.forEach(function(n){n.multiplyWith(t.clone())})},x.prototype.multiplyLinear=function(t){var n=this._terms,e=[];t._terms.forEach(function(t){n.forEach(function(n){var i=n.clone();i.multiplyWith(t.clone()),e.push(i)})}),e.sort(I.Comparer),this._terms=e},x.prototype.isZero=function(){return 0===this._terms.length},x.prototype.clone=function(){var t=new x;return this._terms.forEach(function(n){t._terms.push(n.clone())}),t},x.prototype.coalesceWith=function(t){var n=this;t._terms.forEach(function(t){n.addTerm(t)})},x.prototype.expandState=function(t){var n=[];this._terms.forEach(function(e){var i=[],r=new I(e._coefficient);e._parts.forEach(function(t){t instanceof w?i.push(t._index):t instanceof JellyBFLinearOutputRef&&r.push(t)});var o=new x;o.addTerm(I.makeConstant(1)),i.forEach(function(n){var e=t._data.findIndex(A.FinderEqualIndex(n)),i=new x;i.addTerm(I.makeFromPart(new w(n))),e!==-1&&i.coalesceWith(t._data[e]._combination.clone()),o.multiplyLinear(i)}),o.multiplyTerm(r),o._terms.forEach(function(t){n.push(t)})}),this._terms=[];var e=this;n.forEach(function(t){e.addTerm(t)})},x.IsExactSame=function(t,n){if(t._terms.length!==n._terms.length)return!1;for(var e=t._terms.length,i=0;e>i;++i){if(!I.IsEqual(t._terms[i],n._terms[i]))return!1;if(t._terms[i]._coefficient!==n._terms[i]._coefficient)return!1}return!0};var A=function(t){this._index=t,this._combination=new x};A.Comparer=function(t,n){return t._index-n._index},A.FinderLow=function(t){return function(n){return n._index>=t._index}},A.FinderLowIndex=function(t){return function(n){return n._index>=t}},A.FinderEqual=function(t){return function(n){return n._index===t._index}},A.FinderEqualIndex=function(t){return function(n){return n._index===t}},A.IsEqual=function(t,n){return t._index===n._index},A.IsEqualIndex=function(t,n){return t._index===n},A.prototype.addTerm=function(t){this._combination.addTerm(t)},A.prototype.multiplyTerm=function(t){this._combination.multiplyTerm(t)},A.prototype.isZero=function(){return this._combination.isZero()},A.prototype.coalesceWith=function(t){this._combination.coalesceWith(t._combination)},A.makeFromTerm=function(t,n){var e=new A(t);return e.addTerm(n),e};var g=function(){this._data=[],this._outputs=[],this._exitindex=0,this._inputcount=0};g.prototype.addEntry=function(t){var n=this._data.findIndex(A.FinderLow(t));n===-1?this._data.push(t):A.IsEqual(this._data[n],t)?(this._data[n].coalesceWith(t),this._data[n].isZero()&&this._data.splice(n,1)):this._data.splice(n,0,t)},g.prototype.addDelta=function(t,n){var e=this._data.findIndex(A.FinderLowIndex(t));e===-1?0!==n&&this._data.push(A.makeFromTerm(t,I.makeConstant(n))):A.IsEqualIndex(this._data[e],t)?(this._data[e].addTerm(I.makeConstant(n)),this._data[e].isZero()&&this._data.splice(e,1)):0!==n&&this._data.splice(e,0,A.makeFromTerm(t,I.makeConstant(n)))},g.prototype.addExitDelta=function(t){this._exitindex+=t},g.prototype.coalesceWith=function(t){var n=this,e=this._exitindex,i=this._inputcount;t._data.forEach(function(t){t._index+=e,t._combination._terms.forEach(function(t){t._parts.forEach(function(t){t.addShift(e,i)})})}),t._outputs.forEach(function(t){t._terms.forEach(function(t){t._parts.forEach(function(t){t.addShift(e,i)})})});var r=[];t._data.forEach(function(t){t._combination.expandState(n),r.push(t)}),t._outputs.forEach(function(t){t.expandState(n),n._outputs.push(t)}),r.forEach(function(t){n.addEntry(t)});for(var o=this._data.length-1;o>=0;--o)this._data[o].isZero()&&this._data.splice(o,1);this._exitindex+=t._exitindex,this._inputcount+=t._inputcount},g.prototype.wrapWithLoop=function(){if(0===this._exitindex){var t=this._data.findIndex(A.FinderEqualIndex(0));if(t===-1)return!1;if(x.IsExactSame(this._data[t]._combination,A.makeFromTerm(0,I.makeConstant(-1))._combination)){var n=!0;return this._data.forEach(function(t){t._combination._terms.forEach(function(t){0!==t._parts.length&&(n=!1)})}),!!n&&(this._data.forEach(function(t){var n=new I(1);n._parts.push(new w(0)),t.multiplyTerm(n)}),!0)}return!1}return!1},g.prototype.writeCode=function(){};var E=function(t,n){this._index=t,this._value=n};E.FinderLowIndex=function(t){return function(n){return n._index>=t}};var b=function(t){this.emptyIsZero=t,this._data=[]};b.prototype.getState=function(t){var n=this._data.findIndex(E.FinderLowIndex(t));return n===-1?this.emptyIsZero?0:void 0:this._data[n]._value},b.prototype.setState=function(t,n){var e=this._data.findIndex(E.FinderLowIndex(t));e===-1?(this.emptyIsZero&&0!==n||!this.emptyIsZero&&void 0!==n)&&this._data.splice(e,0,new E(t,n)):this.emptyIsZero&&0===n||!this.emptyIsZero&&void 0===n?this._data.splice(e,1):this._data[e]._value=n};var R=function(t,n){t.length>0&&t[t.length-1]instanceof g?t[t.length-1].coalesceWith(n):t.push(n)},T=function(t,n){if(t.length>0&&"["===t[t.length-1])n.infiniteloops?t.push("]"):t.pop();else if(t.length>1&&t[t.length-1]instanceof g&&"["===t[t.length-2]){var e=t.pop();e.wrapWithLoop(n)?(t.pop(),R(t,e)):(t.push(e),t.push("]"))}else t.push("]")},B={compile:function(t,n){return WebAssembly.Module(p.compile(t,n))},execute:function(n,e,i){i.eof_value=i.eof_value||0;var r=0,o=new t,s=function(){return e.length>r?e[r++]:i.eof_value},a=function(t){o.push(t)};return WebAssembly.instantiate(n,{interaction:{input:s,output:a}}).exports.main(),o.toUint8Array()},executeInteractive:function(t,n,e,i,r,o){var s={READ_HEAD:0,WRITE_HEAD:1,TERMINATED_FLAG:2};o.bufferlength=o.bufferlength||1024,o.eof_value=o.eof_value||0;var a=0,c=0,u=!1,_=function(){if(a===c&&(Atomics.wait(i,s.WRITE_HEAD,c),c=Atomics.load(i,s.WRITE_HEAD),u||(u=0!==Atomics.load(i,s.TERMINATED_FLAG))),!u||c>a+1){var t=Atomics.load(n,a++%o.bufferlength);return Atomics.store(i,s.READ_HEAD,a),t}return o.eof_value},h=0,p=0,f=function(t){h+o.bufferlength===p&&(Atomics.wait(r,s.READ_HEAD,h),h=Atomics.load(r,s.READ_HEAD)),Atomics.store(e,p++%o.bufferlength,t),Atomics.store(r,s.WRITE_HEAD,p)},d=function(){h+o.bufferlength===p&&(Atomics.wait(r,s.READ_HEAD,h),h=Atomics.load(r,s.READ_HEAD)),Atomics.store(r,s.TERMINATED_FLAG,1),Atomics.store(r,s.WRITE_HEAD,p+1)};return WebAssembly.instantiate(t,{interaction:{input:_,output:f}}).exports.main(),d(),!0}};!function(){self.addEventListener("message",function(t){var n=t.data;switch(n.type){case"compile":var e=n.sourcecode,i=n.options,r=B.compile(e,i);self.postMessage({type:"compiled",module:r},[r]);break;case"execute-interactive":var r=n.module,o=n.inputbuffer,s=n.outputbuffer,a=n.inputwaitbuffer,c=n.outputwaitbuffer,i=n.options;B.executeInteractive(r,UInt8Array(o),UInt8Array(s),Int32Array(a),Int32Array(c),i),self.postMessage({type:"executed"});break;case"execute":var r=n.module,u=n.inputuint8array,i=n.options,_=B.execute(r,u,i);self.postMessage({type:"executed",outputuint8array:_},[_])}}),self.postMessage({type:"ready"})}(); \ No newline at end of file diff --git a/join-worker.bat b/join-worker.bat new file mode 100644 index 0000000..4c644fe --- /dev/null +++ b/join-worker.bat @@ -0,0 +1 @@ +call uglifyjs wasm32codegen.max.js jelly-bf-compiler.js jelly-bf-sync.js jelly-bf-worker.js --beautify --output jelly-bf-worker.max.js \ No newline at end of file diff --git a/main-old.js b/main-old.js new file mode 100644 index 0000000..f839a00 --- /dev/null +++ b/main-old.js @@ -0,0 +1,30 @@ +window.addEventListener("load",function(){ + if(!window.WebAssembly){ + alert("This browser does not support WebAssembly. Chrome 57+, Firefox 52+ and Opera 44+ are great browsers that do support WebAssembly, and they're free!"); + return; + } + var codeTextbox=document.getElementById("codetextbox"); + var inputTextbox=document.getElementById("inputtextbox"); + var outputTextbox=document.getElementById("outputtextbox"); + var codeButton=document.getElementById("codebutton"); + var clearOutputButton=document.getElementById("clearoutputbutton"); + codeButton.addEventListener("click",function(){ + var codestr=codeTextbox.value; + var instr=inputTextbox.value; + outputTextbox.value=""; + var startTime=Date.now(); + JellyBF.compileOptimized(codestr,{infiniteloops:false},function(compiledModule){ + var compiledTime=Date.now(); + console.log("Compiled in "+Math.round(compiledTime-startTime)+" ms."); + compiledTime=Date.now(); + JellyBF.execute(compiledModule,instr,function(outstr){ + var executedTime=Date.now(); + console.log("Executed in "+Math.round(executedTime-compiledTime)+" ms."); + outputTextbox.value=outstr; + }); + }); + }); + clearOutputButton.addEventListener("click",function(){ + outputTextbox.value=""; + }); +}); \ No newline at end of file diff --git a/main.js b/main.js index f839a00..e11b850 100644 --- a/main.js +++ b/main.js @@ -8,12 +8,50 @@ window.addEventListener("load",function(){ var outputTextbox=document.getElementById("outputtextbox"); var codeButton=document.getElementById("codebutton"); var clearOutputButton=document.getElementById("clearoutputbutton"); + + + var wait_for_message=function(worker,type,callback){ + var message_handler=function(e){ + switch(e.data.type){ + case type: + worker.removeEventListener("message",message_handler); + callback(e.data); + break; + } + }; + worker.addEventListener("message",message_handler); + }; + + + var initworker=function(callback){ + var worker=new Worker("jelly-bf-worker.max.js"); + wait_for_message(worker,"ready",function(){ + callback(worker); + }); + }; + + var compile=function(worker,sourcecode,options,callback){ + var module=new Uint8Array(100); + worker.postMessage({type:"compile",sourcecode:sourcecode,options:options,module:module},[module.buffer]); + wait_for_message(worker,"compiled",function(message){ + callback(); + }); + }; + + var execute=function(worker,inputstr,options,callback){ + var encodedinput=new TextEncoder().encode(inputstr); + worker.postMessage({type:"execute",inputuint8array:encodedinput,options:options},[encodedinput.buffer]); + wait_for_message(worker,"executed",function(message){ + callback(new TextDecoder().decode(message.outputuint8array)); + }); + }; + codeButton.addEventListener("click",function(){ var codestr=codeTextbox.value; var instr=inputTextbox.value; outputTextbox.value=""; - var startTime=Date.now(); - JellyBF.compileOptimized(codestr,{infiniteloops:false},function(compiledModule){ + + /*JellyBF.compileOptimized(codestr,{infiniteloops:false},function(compiledModule){ var compiledTime=Date.now(); console.log("Compiled in "+Math.round(compiledTime-startTime)+" ms."); compiledTime=Date.now(); @@ -22,7 +60,20 @@ window.addEventListener("load",function(){ console.log("Executed in "+Math.round(executedTime-compiledTime)+" ms."); outputTextbox.value=outstr; }); + });*/ + initworker(function(worker){ + var startTime=Date.now(); + compile(worker, codestr,{},function(){ + var compiledTime=Date.now(); + console.log("Compiled in "+Math.round(compiledTime-startTime)+" ms."); + execute(worker,instr,{},function(outstr){ + var executedTime=Date.now(); + console.log("Executed in "+Math.round(executedTime-compiledTime)+" ms."); + outputTextbox.value=outstr; + }); + }); }); + }); clearOutputButton.addEventListener("click",function(){ outputTextbox.value=""; diff --git a/uglify-worker.bat b/uglify-worker.bat new file mode 100644 index 0000000..e02a929 --- /dev/null +++ b/uglify-worker.bat @@ -0,0 +1 @@ +call uglifyjs wasm32codegen.max.js jelly-bf-compiler.js jelly-bf-sync.js jelly-bf-worker.js --mangle toplevel --compress sequences,unsafe,comparisons,unsafe_comps,pure_getters,collapse_vars,reduce_vars,keep_fargs=false,passes=5 --screw-ie8 --output jelly-bf-worker.min.js \ No newline at end of file