diff options
Diffstat (limited to 'src/embind/emval.js')
-rw-r--r-- | src/embind/emval.js | 258 |
1 files changed, 215 insertions, 43 deletions
diff --git a/src/embind/emval.js b/src/embind/emval.js index 9574ab37..77270597 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -1,111 +1,283 @@ -/*global Module*/ +/*global Module:true, Runtime*/ /*global HEAP32*/ -/*global Pointer_stringify, writeStringToMemory*/ -/*global requireRegisteredType*/ +/*global new_*/ +/*global createNamedFunction*/ +/*global readLatin1String, writeStringToMemory*/ +/*global requireRegisteredType, throwBindingError*/ -var _emval_handle_array = []; +var Module = Module || {}; + +var _emval_handle_array = [{}]; // reserve zero var _emval_free_list = []; // Public JS API /** @expose */ Module.count_emval_handles = function() { - return _emval_handle_array.length; + var count = 0; + for (var i = 1; i < _emval_handle_array.length; ++i) { + if (_emval_handle_array[i] !== undefined) { + ++count; + } + } + return count; +}; + +/** @expose */ +Module.get_first_emval = function() { + for (var i = 1; i < _emval_handle_array.length; ++i) { + if (_emval_handle_array[i] !== undefined) { + return _emval_handle_array[i]; + } + } + return null; }; // Private C++ API +var _emval_symbols = {}; // address -> string + +function __emval_register_symbol(address) { + _emval_symbols[address] = readLatin1String(address); +} + +function getStringOrSymbol(address) { + var symbol = _emval_symbols[address]; + if (symbol === undefined) { + return readLatin1String(address); + } else { + return symbol; + } +} + +function requireHandle(handle) { + if (!handle) { + throwBindingError('Cannot use deleted val. handle = ' + handle); + } +} + function __emval_register(value) { var handle = _emval_free_list.length ? _emval_free_list.pop() : _emval_handle_array.length; + _emval_handle_array[handle] = {refcount: 1, value: value}; return handle; } function __emval_incref(handle) { - _emval_handle_array[handle].refcount += 1; + if (handle) { + _emval_handle_array[handle].refcount += 1; + } } function __emval_decref(handle) { - if (0 === --_emval_handle_array[handle].refcount) { - delete _emval_handle_array[handle]; + if (handle && 0 === --_emval_handle_array[handle].refcount) { + _emval_handle_array[handle] = undefined; _emval_free_list.push(handle); - - var actual_length = _emval_handle_array.length; - while (actual_length > 0 && _emval_handle_array[actual_length - 1] === undefined) { - --actual_length; - } - _emval_handle_array.length = actual_length; } } +function __emval_new_array() { + return __emval_register([]); +} + function __emval_new_object() { return __emval_register({}); } -function __emval_new_long(value) { - return __emval_register(value); +function __emval_undefined() { + return __emval_register(undefined); +} + +function __emval_null() { + return __emval_register(null); } -function __emval_new_cstring(str) { - return __emval_register(Pointer_stringify(str)); +function __emval_new_cstring(v) { + return __emval_register(getStringOrSymbol(v)); +} + +function __emval_take_value(type, v) { + type = requireRegisteredType(type, '_emval_take_value'); + v = type.fromWireType(v); + return __emval_register(v); +} + +var __newers = {}; // arity -> function + + +function craftEmvalAllocator(argCount) { + /*This function returns a new function that looks like this: + function emval_allocator_3(handle, argTypes, arg0Wired, arg1Wired, arg2Wired) { + var argType0 = requireRegisteredType(HEAP32[(argTypes >> 2)], "parameter 0"); + var arg0 = argType0.fromWireType(arg0Wired); + var argType1 = requireRegisteredType(HEAP32[(argTypes >> 2) + 1], "parameter 1"); + var arg1 = argType1.fromWireType(arg1Wired); + var argType2 = requireRegisteredType(HEAP32[(argTypes >> 2) + 2], "parameter 2"); + var arg2 = argType2.fromWireType(arg2Wired); + var constructor = _emval_handle_array[handle].value; + var emval = new constructor(arg0, arg1, arg2); + return emval; + } */ + + var args1 = ["requireRegisteredType", "HEAP32", "_emval_handle_array", "__emval_register"]; + var args2 = [requireRegisteredType, HEAP32, _emval_handle_array, __emval_register]; + + var argsList = ""; + var argsListWired = ""; + for(var i = 0; i < argCount; ++i) { + argsList += (i!==0?", ":"")+"arg"+i; // 'arg0, arg1, ..., argn' + argsListWired += ", arg"+i+"Wired"; // ', arg0Wired, arg1Wired, ..., argnWired' + } + + var invokerFnBody = + "return function emval_allocator_"+argCount+"(handle, argTypes " + argsListWired + ") {\n"; + + for(var i = 0; i < argCount; ++i) { + invokerFnBody += + "var argType"+i+" = requireRegisteredType(HEAP32[(argTypes >> 2) + "+i+"], \"parameter "+i+"\");\n" + + "var arg"+i+" = argType"+i+".fromWireType(arg"+i+"Wired);\n"; + } + invokerFnBody += + "var constructor = _emval_handle_array[handle].value;\n" + + "var obj = new constructor("+argsList+");\n" + + "return __emval_register(obj);\n" + + "}\n"; + + args1.push(invokerFnBody); + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; } -function __emval_get_property(handle, k) { - k = Pointer_stringify(k); - return __emval_register(_emval_handle_array[handle].value[k]); +function __emval_new(handle, argCount, argTypes) { + requireHandle(handle); + + var newer = __newers[argCount]; + if (!newer) { + newer = craftEmvalAllocator(argCount); + __newers[argCount] = newer; + } + + if (argCount === 0) { + return newer(handle, argTypes); + } else if (argCount === 1) { + return newer(handle, argTypes, arguments[3]); + } else if (argCount === 2) { + return newer(handle, argTypes, arguments[3], arguments[4]); + } else if (argCount === 3) { + return newer(handle, argTypes, arguments[3], arguments[4], arguments[5]); + } else if (argCount === 4) { + return newer(handle, argTypes, arguments[3], arguments[4], arguments[5], arguments[6]); + } else { + // This is a slow path! (.apply and .splice are slow), so a few specializations are present above. + return newer.apply(null, arguments.splice(1)); + } } -function __emval_get_property_by_long(handle, k) { - return __emval_register(_emval_handle_array[handle].value[k]); +// appease jshint (technically this code uses eval) +var global = (function(){return Function;})()('return this')(); + +function __emval_get_global(name) { + name = getStringOrSymbol(name); + return __emval_register(global[name]); } -function __emval_get_property_by_unsigned_long(handle, k) { - return __emval_register(_emval_handle_array[handle].value[k]); +function __emval_get_module_property(name) { + name = getStringOrSymbol(name); + return __emval_register(Module[name]); } -function __emval_set_property(handle, k, value) { - k = Pointer_stringify(k); - _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +function __emval_get_property(handle, key) { + requireHandle(handle); + return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]); } -function __emval_set_property_by_int(handle, k, value) { - _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +function __emval_set_property(handle, key, value) { + requireHandle(handle); + _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value; } function __emval_as(handle, returnType) { + requireHandle(handle); returnType = requireRegisteredType(returnType, 'emval::as'); var destructors = []; // caller owns destructing return returnType.toWireType(destructors, _emval_handle_array[handle].value); } -function __emval_call(handle, argCount, argTypes) { - var args = Array.prototype.slice.call(arguments, 3); - var fn = _emval_handle_array[handle].value; +function parseParameters(argCount, argTypes, argWireTypes) { var a = new Array(argCount); for (var i = 0; i < argCount; ++i) { var argType = requireRegisteredType( HEAP32[(argTypes >> 2) + i], "parameter " + i); - a[i] = argType.fromWireType(args[i]); + a[i] = argType.fromWireType(argWireTypes[i]); + } + return a; +} + +function __emval_call(handle, argCount, argTypes) { + requireHandle(handle); + var types = lookupTypes(argCount, argTypes); + + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = types[i].fromWireType(arguments[3 + i]); } - var rv = fn.apply(undefined, a); + + var fn = _emval_handle_array[handle].value; + var rv = fn.apply(undefined, args); return __emval_register(rv); } -function __emval_call_method(handle, name, argCount, argTypes) { - name = Pointer_stringify(name); - var args = Array.prototype.slice.call(arguments, 4); - var obj = _emval_handle_array[handle].value; +function lookupTypes(argCount, argTypes, argWireTypes) { var a = new Array(argCount); for (var i = 0; i < argCount; ++i) { - var argType = requireRegisteredType( + a[i] = requireRegisteredType( HEAP32[(argTypes >> 2) + i], "parameter " + i); - a[i] = argType.fromWireType(args[i]); } - var rv = obj[name].apply(obj, a); - return __emval_register(rv); + return a; +} + +function __emval_get_method_caller(argCount, argTypes) { + var types = lookupTypes(argCount, argTypes); + + var retType = types[0]; + var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; + + var args1 = ["Runtime", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"]; + var args2 = [Runtime, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType]; + + var argsList = ""; // 'arg0, arg1, arg2, ... , argN' + var argsListWired = ""; // 'arg0Wired, ..., argNWired' + for (var i = 0; i < argCount - 1; ++i) { + argsList += (i !== 0 ? ", " : "") + "arg" + i; + argsListWired += ", arg" + i + "Wired"; + args1.push("argType" + i); + args2.push(types[1 + i]); + } + + var invokerFnBody = + "return Runtime.addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" + + "requireHandle(handle);\n" + + "name = getStringOrSymbol(name);\n"; + + for (var i = 0; i < argCount - 1; ++i) { + invokerFnBody += "var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n"; + } + invokerFnBody += + "var obj = _emval_handle_array[handle].value;\n" + + "return retType.toWireType(null, obj[name](" + argsList + "));\n" + + "}));\n"; + + args1.push(invokerFnBody); + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; +} + +function __emval_has_function(handle, name) { + name = getStringOrSymbol(name); + return _emval_handle_array[handle].value[name] instanceof Function; } |