aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-04-16 14:03:43 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-04-16 14:03:43 -0700
commit985765d9a5b2dcca05bc5f8401e3d2423964d0f2 (patch)
tree994fa25d2d1eee8688e7b334a186081a5b679739
parent3cbdfcc318e45219edbe78c21cd25fe23f5c1c52 (diff)
parent8ae67d7642ebdd77a3c5f0d8fa7115fb372e98ff (diff)
Merge pull request #1044 from imvu/embind_update
Embind update
-rw-r--r--AUTHORS13
-rwxr-xr-x[-rw-r--r--]src/embind/embind.js1507
-rwxr-xr-x[-rw-r--r--]src/embind/emval.js147
-rwxr-xr-x[-rw-r--r--]system/include/emscripten/bind.h1227
-rw-r--r--system/include/emscripten/val.h224
-rwxr-xr-x[-rw-r--r--]system/include/emscripten/wire.h267
-rwxr-xr-xsystem/lib/embind/bind.cpp83
-rwxr-xr-xtests/embind/embind.test.js1587
-rw-r--r--tests/embind/embind_test.cpp1874
-rw-r--r--tests/embind/embind_test.js393
-rwxr-xr-xtests/embind/imvu_test_adapter.js616
-rwxr-xr-xtests/embind/underscore-1.4.2.js1200
-rwxr-xr-xtests/runner.py54
13 files changed, 7763 insertions, 1429 deletions
diff --git a/AUTHORS b/AUTHORS
index 87a656d6..1c6cf0ec 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -24,7 +24,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Pierre Renaux <pierre@talansoft.com>
* Brian Anderson <banderson@mozilla.com>
* Jon Bardin <diclophis@gmail.com>
-* Jukka Jylänki <jujjyl@gmail.com>
+* Jukka Jylänki <jujjyl@gmail.com>
* Aleksander Guryanov <caiiiycuk@gmail.com>
* Chad Austin <chad@chadaustin.me> (copyright owned by IMVU)
* nandhp <nandhp@gmail.com>
@@ -46,7 +46,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Anthony Liot <wolfviking0@yahoo.com>
* Michael Riss <Michael.Riss@gmx.de>
* Jasper St. Pierre <jstpierre@mecheye.net>
-* Manuel Schölling <manuel.schoelling@gmx.de>
+* Manuel Schölling <manuel.schoelling@gmx.de>
* Bruce Mitchener, Jr. <bruce.mitchener@gmail.com>
* Michael Bishop <mbtyke@gmail.com>
* Roger Braun <roger@rogerbraun.net>
@@ -57,9 +57,14 @@ a license to everyone to use it as detailed in LICENSE.)
* Ting-Yuan Huang <thuang@mozilla.com>
* Joshua Granick <jgranick@blackberry.com>
* Felix H. Dahlke <fhd@ubercode.de>
-* Éloi Rivard <azmeuk@gmail.com>
+* Éloi Rivard <azmeuk@gmail.com>
* Alexander Gladysh <ag@logiceditor.com>
* Arlo Breault <arlolra@gmail.com>
* Jacob Lee <artdent@gmail.com> (copyright owned by Google, Inc.)
* Joe Lee <jlee@imvu.com> (copyright owned by IMVU)
-
+* Andy Friesen <andy@imvu.com> (copyright owned by IMVU)
+* Bill Welden <bwelden@imvu.com> (copyright owned by IMVU)
+* Michael Ey <mey@imvu.com> (copyright owned by IMVU)
+* Llorens Marti Garcia <lgarcia@imvu.com> (copyright owned by IMVU)
+* Jinsuck Kim <jkim@imvu.com> (copyright owned by IMVU)
+* Todd Lee <tlee@imvu.com> (copyright owned by IMVU)
diff --git a/src/embind/embind.js b/src/embind/embind.js
index d40d6ca2..ee717f4b 100644..100755
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -1,14 +1,141 @@
/*global Module*/
/*global _malloc, _free, _memcpy*/
-/*global FUNCTION_TABLE, HEAP32*/
-/*global Pointer_stringify, writeStringToMemory*/
+/*global FUNCTION_TABLE, HEAP32, HEAPU8*/
+/*global Pointer_stringify*/
/*global __emval_register, _emval_handle_array, __emval_decref*/
+/*global ___getTypeName*/
+var InternalError = Module.InternalError = extendError(Error, 'InternalError');
+var BindingError = Module.BindingError = extendError(Error, 'BindingError');
+var UnboundTypeError = Module.UnboundTypeError = extendError(BindingError, 'UnboundTypeError');
+
+function throwInternalError(message) {
+ throw new InternalError(message);
+}
+
+function throwBindingError(message) {
+ throw new BindingError(message);
+}
+
+function throwUnboundTypeError(message, types) {
+ var unboundTypes = [];
+ var seen = {};
+ function visit(type) {
+ if (seen[type]) {
+ return;
+ }
+ if (registeredTypes[type]) {
+ return;
+ }
+ if (typeDependencies[type]) {
+ typeDependencies[type].forEach(visit);
+ return;
+ }
+ unboundTypes.push(type);
+ seen[type] = true;
+ }
+ types.forEach(visit);
+
+ throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', ']));
+}
+
+// Creates a function overload resolution table to the given method 'methodName' in the given prototype,
+// if the overload table doesn't yet exist.
+function ensureOverloadTable(proto, methodName, humanName) {
+ if (undefined === proto[methodName].overloadTable) {
+ var prevFunc = proto[methodName];
+ // Inject an overload resolver function that routes to the appropriate overload based on the number of arguments.
+ proto[methodName] = function() {
+ // TODO This check can be removed in -O3 level "unsafe" optimizations.
+ if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) {
+ throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!");
+ }
+ return proto[methodName].overloadTable[arguments.length].apply(this, arguments);
+ };
+ // Move the previous function into the overload table.
+ proto[methodName].overloadTable = [];
+ proto[methodName].overloadTable[prevFunc.argCount] = prevFunc;
+ }
+}
+
+/* Registers a symbol (function, class, enum, ...) as part of the Module JS object so that
+ hand-written code is able to access that symbol via 'Module.name'.
+ name: The name of the symbol that's being exposed.
+ value: The object itself to expose (function, class, ...)
+ numArguments: For functions, specifies the number of arguments the function takes in. For other types, unused and undefined.
+
+ To implement support for multiple overloads of a function, an 'overload selector' function is used. That selector function chooses
+ the appropriate overload to call from an function overload table. This selector function is only used if multiple overloads are
+ actually registered, since it carries a slight performance penalty. */
+function exposePublicSymbol(name, value, numArguments) {
+ if (Module.hasOwnProperty(name)) {
+ if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) {
+ throwBindingError("Cannot register public name '" + name + "' twice");
+ }
+
+ // We are exposing a function with the same name as an existing function. Create an overload table and a function selector
+ // that routes between the two.
+ ensureOverloadTable(Module, name, name);
+ if (Module.hasOwnProperty(numArguments)) {
+ throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!");
+ }
+ // Add the new function into the overload table.
+ Module[name].overloadTable[numArguments] = value;
+ }
+ else {
+ Module[name] = value;
+ if (undefined !== numArguments) {
+ Module[name].numArguments = numArguments;
+ }
+ }
+}
+
+function replacePublicSymbol(name, value, numArguments) {
+ if (!Module.hasOwnProperty(name)) {
+ throwInternalError('Replacing nonexistant public symbol');
+ }
+ // If there's an overload table for this symbol, replace the symbol in the overload table instead.
+ if (undefined !== Module[name].overloadTable && undefined !== numArguments) {
+ Module[name].overloadTable[numArguments] = value;
+ }
+ else {
+ Module[name] = value;
+ }
+}
+
+// from https://github.com/imvu/imvujs/blob/master/src/error.js
+function extendError(baseErrorType, errorName) {
+ var errorClass = createNamedFunction(errorName, function(message) {
+ this.name = errorName;
+ this.message = message;
+
+ var stack = (new Error(message)).stack;
+ if (stack !== undefined) {
+ this.stack = this.toString() + '\n' +
+ stack.replace(/^Error(:[^\n]*)?\n/, '');
+ }
+ });
+ errorClass.prototype = Object.create(baseErrorType.prototype);
+ errorClass.prototype.constructor = errorClass;
+ errorClass.prototype.toString = function() {
+ if (this.message === undefined) {
+ return this.name;
+ } else {
+ return this.name + ': ' + this.message;
+ }
+ };
+
+ return errorClass;
+}
+
+
+// from https://github.com/imvu/imvujs/blob/master/src/function.js
function createNamedFunction(name, body) {
/*jshint evil:true*/
return new Function(
"body",
"return function " + name + "() {\n" +
+ " \"use strict\";" +
" return body.apply(this, arguments);\n" +
"};\n"
)(body);
@@ -23,136 +150,213 @@ function _embind_repr(v) {
}
}
-var typeRegistry = {};
+// typeID -> { toWireType: ..., fromWireType: ... }
+var registeredTypes = {};
+
+// typeID -> [callback]
+var awaitingDependencies = {};
+
+// typeID -> [dependentTypes]
+var typeDependencies = {};
+
+// class typeID -> {pointerType: ..., constPointerType: ...}
+var registeredPointers = {};
+
+function registerType(rawType, registeredInstance) {
+ var name = registeredInstance.name;
+ if (!rawType) {
+ throwBindingError('type "' + name + '" must have a positive integer typeid pointer');
+ }
+ if (registeredTypes.hasOwnProperty(rawType)) {
+ throwBindingError("Cannot register type '" + name + "' twice");
+ }
+
+ registeredTypes[rawType] = registeredInstance;
+ delete typeDependencies[rawType];
+
+ if (awaitingDependencies.hasOwnProperty(rawType)) {
+ var callbacks = awaitingDependencies[rawType];
+ delete awaitingDependencies[rawType];
+ callbacks.forEach(function(cb) {
+ cb();
+ });
+ }
+}
+
+function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) {
+ myTypes.forEach(function(type) {
+ typeDependencies[type] = dependentTypes;
+ });
-function validateType(type, name) {
- if (!type) {
- throw new BindingError('type "' + name + '" must have a positive integer typeid pointer');
+ function onComplete(typeConverters) {
+ var myTypeConverters = getTypeConverters(typeConverters);
+ if (myTypeConverters.length !== myTypes.length) {
+ throwInternalError('Mismatched type converter count');
+ }
+ for (var i = 0; i < myTypes.length; ++i) {
+ registerType(myTypes[i], myTypeConverters[i]);
+ }
}
- if (undefined !== typeRegistry[type]) {
- throw new BindingError('cannot register type "' + name + '" twice');
+
+ var typeConverters = new Array(dependentTypes.length);
+ var unregisteredTypes = [];
+ var registered = 0;
+ dependentTypes.forEach(function(dt, i) {
+ if (registeredTypes.hasOwnProperty(dt)) {
+ typeConverters[i] = registeredTypes[dt];
+ } else {
+ unregisteredTypes.push(dt);
+ if (!awaitingDependencies.hasOwnProperty(dt)) {
+ awaitingDependencies[dt] = [];
+ }
+ awaitingDependencies[dt].push(function() {
+ typeConverters[i] = registeredTypes[dt];
+ ++registered;
+ if (registered === unregisteredTypes.length) {
+ onComplete(typeConverters);
+ }
+ });
+ }
+ });
+ if (0 === unregisteredTypes.length) {
+ onComplete(typeConverters);
}
}
-function __embind_register_void(voidType, name) {
+function getTypeName(type) {
+ var ptr = ___getTypeName(type);
+ var rv = Pointer_stringify(ptr);
+ _free(ptr);
+ return rv;
+}
+
+function heap32VectorToArray(count, firstElement) {
+ var array = [];
+ for (var i = 0; i < count; i++) {
+ array.push(HEAP32[(firstElement >> 2) + i]);
+ }
+ return array;
+}
+
+function requireRegisteredType(rawType, humanName) {
+ var impl = registeredTypes[rawType];
+ if (undefined === impl) {
+ throwBindingError(humanName + " has unknown type " + getTypeName(rawType));
+ }
+ return impl;
+}
+
+function __embind_register_void(rawType, name) {
name = Pointer_stringify(name);
- validateType(voidType, name);
- typeRegistry[voidType] = {
+ registerType(rawType, {
name: name,
fromWireType: function() {
return undefined;
- }
- };
+ },
+ });
}
-function __embind_register_bool(boolType, name, trueValue, falseValue) {
+function __embind_register_bool(rawType, name, trueValue, falseValue) {
name = Pointer_stringify(name);
- validateType(boolType, name);
- typeRegistry[boolType] = {
+ registerType(rawType, {
name: name,
+ fromWireType: function(wt) {
+ // ambiguous emscripten ABI: sometimes return values are
+ // true or false, and sometimes integers (0 or 1)
+ return !!wt;
+ },
toWireType: function(destructors, o) {
return o ? trueValue : falseValue;
},
- fromWireType: function(wt) {
- return wt === trueValue;
- },
- };
+ });
}
-function __embind_register_integer(primitiveType, name) {
+// When converting a number from JS to C++ side, the valid range of the number is
+// [minRange, maxRange], inclusive.
+function __embind_register_integer(primitiveType, name, minRange, maxRange) {
name = Pointer_stringify(name);
- validateType(primitiveType, name);
- typeRegistry[primitiveType] = {
+ if (maxRange === -1) { // LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come out as 'i32 -1'. Always treat those as max u32.
+ maxRange = 4294967295;
+ }
+ registerType(primitiveType, {
name: name,
+ minRange: minRange,
+ maxRange: maxRange,
+ fromWireType: function(value) {
+ return value;
+ },
toWireType: function(destructors, value) {
+ // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could
+ // avoid the following two if()s and assume value is of proper type.
if (typeof value !== "number") {
- throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name);
+ throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name);
+ }
+ if (value < minRange || value > maxRange) {
+ throw new TypeError('Passing a number "' + _embind_repr(value) + '" from JS side to C/C++ side to an argument of type "' + name + '", which is outside the valid range [' + minRange + ', ' + maxRange + ']!');
}
return value | 0;
},
- fromWireType: function(value) {
- return value;
- }
- };
+ });
}
-function __embind_register_float(primitiveType, name) {
+function __embind_register_float(rawType, name) {
name = Pointer_stringify(name);
- validateType(primitiveType, name);
- typeRegistry[primitiveType] = {
+ registerType(rawType, {
name: name,
+ fromWireType: function(value) {
+ return value;
+ },
toWireType: function(destructors, value) {
+ // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could
+ // avoid the following if() and assume value is of proper type.
if (typeof value !== "number") {
- throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name);
+ throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' +this.name);
}
return value;
},
- fromWireType: function(value) {
- return value;
- }
- };
+ });
}
-function __embind_register_cstring(stringType, name) {
+function __embind_register_cstring(rawType, name) {
name = Pointer_stringify(name);
- validateType(stringType, name);
- typeRegistry[stringType] = {
+ registerType(rawType, {
name: name,
+ fromWireType: function(value) {
+ var length = HEAP32[value >> 2];
+ var a = new Array(length);
+ for (var i = 0; i < length; ++i) {
+ a[i] = String.fromCharCode(HEAPU8[value + 4 + i]);
+ }
+ _free(value);
+ return a.join('');
+ },
toWireType: function(destructors, value) {
- var ptr = _malloc(value.length + 1);
- writeStringToMemory(value, ptr);
- destructors.push(_free);
- destructors.push(ptr);
+ // assumes 4-byte alignment
+ var length = value.length;
+ var ptr = _malloc(4 + length);
+ HEAP32[ptr >> 2] = length;
+ for (var i = 0; i < length; ++i) {
+ HEAPU8[ptr + 4 + i] = value.charCodeAt(i);
+ }
+ destructors.push(_free, ptr);
return ptr;
},
- fromWireType: function(value) {
- var rv = Pointer_stringify(value);
- _free(value);
- return rv;
- }
- };
+ });
}
-function __embind_register_emval(emvalType, name) {
+function __embind_register_emval(rawType, name) {
name = Pointer_stringify(name);
- validateType(emvalType, name);
- typeRegistry[emvalType] = {
+ registerType(rawType, {
name: name,
- toWireType: function(destructors, value) {
- return __emval_register(value);
- },
fromWireType: function(handle) {
var rv = _emval_handle_array[handle].value;
__emval_decref(handle);
return rv;
- }
- };
-}
-
-var BindingError = Error;
-/** @expose */
-Module.BindingError = BindingError;
-
-function typeName(typeID) {
- // could use our carnal knowledge of RTTI but for now just return the pointer...
- return typeID;
-}
-
-function requireRegisteredType(type, humanName) {
- var impl = typeRegistry[type];
- if (undefined === impl) {
- throw new BindingError(humanName + " has unknown type: " + typeName(type));
- }
- return impl;
-}
-
-function requireArgumentTypes(argCount, argTypes, name) {
- var argTypeImpls = new Array(argCount);
- for (var i = 0; i < argCount; ++i) {
- var argType = HEAP32[(argTypes >> 2) + i];
- argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i);
- }
- return argTypeImpls;
+ },
+ toWireType: function(destructors, value) {
+ return __emval_register(value);
+ },
+ });
}
function runDestructors(destructors) {
@@ -163,427 +367,917 @@ function runDestructors(destructors) {
}
}
-function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) {
- name = Pointer_stringify(name);
- returnType = requireRegisteredType(returnType, "Function " + name + " return value");
- invoker = FUNCTION_TABLE[invoker];
- argTypes = requireArgumentTypes(argCount, argTypes, name);
-
- Module[name] = function() {
- if (arguments.length !== argCount) {
- throw new BindingError('emscripten binding function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount);
+function makeInvoker(name, argCount, argTypes, invoker, fn) {
+ if (!FUNCTION_TABLE[fn]) {
+ throwBindingError('function '+name+' is not defined');
+ }
+ return createNamedFunction(makeLegalFunctionName(name), function() {
+ if (arguments.length !== argCount - 1) {
+ throwBindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1));
}
var destructors = [];
- var args = new Array(argCount + 1);
+ var args = new Array(argCount);
args[0] = fn;
- for (var i = 0; i < argCount; ++i) {
- args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]);
+ for (var i = 1; i < argCount; ++i) {
+ args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]);
}
- var rv = returnType.fromWireType(invoker.apply(null, args));
+ var rv = invoker.apply(null, args);
+ rv = argTypes[0].fromWireType(rv);
runDestructors(destructors);
return rv;
- };
+ });
}
-function __embind_register_tuple(tupleType, name, constructor, destructor) {
+function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) {
+ var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
name = Pointer_stringify(name);
- constructor = FUNCTION_TABLE[constructor];
- destructor = FUNCTION_TABLE[destructor];
+ rawInvoker = FUNCTION_TABLE[rawInvoker];
- var elements = [];
+ exposePublicSymbol(name, function() {
+ throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes);
+ }, argCount - 1);
- typeRegistry[tupleType] = {
- name: name,
- elements: elements,
- fromWireType: function(ptr) {
- var len = elements.length;
- var rv = new Array(len);
- for (var i = 0; i < len; ++i) {
- rv[i] = elements[i].read(ptr);
- }
- destructor(ptr);
- return rv;
- },
- toWireType: function(destructors, o) {
- var len = elements.length;
- if (len !== o.length) {
- throw new TypeError("Incorrect number of tuple elements");
- }
- var ptr = constructor();
- for (var i = 0; i < len; ++i) {
- elements[i].write(ptr, o[i]);
- }
- destructors.push(destructor);
- destructors.push(ptr);
- return ptr;
- }
- };
+ whenDependentTypesAreResolved([], argTypes, function(argTypes) {
+ replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn), argCount - 1);
+ return [];
+ });
}
-function copyMemberPointer(memberPointer, memberPointerSize) {
- var copy = _malloc(memberPointerSize);
- if (!copy) {
- throw new Error('Failed to allocate member pointer copy');
- }
- _memcpy(copy, memberPointer, memberPointerSize);
- return copy;
+var tupleRegistrations = {};
+
+function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) {
+ tupleRegistrations[rawType] = {
+ name: Pointer_stringify(name),
+ rawConstructor: FUNCTION_TABLE[rawConstructor],
+ rawDestructor: FUNCTION_TABLE[rawDestructor],
+ elements: [],
+ };
}
function __embind_register_tuple_element(
- tupleType,
- elementType,
+ rawTupleType,
+ getterReturnType,
getter,
+ getterContext,
+ setterArgumentType,
setter,
- memberPointerSize,
- memberPointer
+ setterContext
) {
- tupleType = requireRegisteredType(tupleType, 'tuple');
- elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]");
- getter = FUNCTION_TABLE[getter];
- setter = FUNCTION_TABLE[setter];
- memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
-
- tupleType.elements.push({
- read: function(ptr) {
- return elementType.fromWireType(getter(ptr, memberPointer));
- },
- write: function(ptr, o) {
- var destructors = [];
- setter(ptr, memberPointer, elementType.toWireType(destructors, o));
- runDestructors(destructors);
- }
+ tupleRegistrations[rawTupleType].elements.push({
+ getterReturnType: getterReturnType,
+ getter: FUNCTION_TABLE[getter],
+ getterContext: getterContext,
+ setterArgumentType: setterArgumentType,
+ setter: FUNCTION_TABLE[setter],
+ setterContext: setterContext,
});
}
-function __embind_register_tuple_element_accessor(
- tupleType,
- elementType,
- staticGetter,
- getterSize,
- getter,
- staticSetter,
- setterSize,
- setter
-) {
- tupleType = requireRegisteredType(tupleType, 'tuple');
- elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]");
- staticGetter = FUNCTION_TABLE[staticGetter];
- getter = copyMemberPointer(getter, getterSize);
- staticSetter = FUNCTION_TABLE[staticSetter];
- setter = copyMemberPointer(setter, setterSize);
-
- tupleType.elements.push({
- read: function(ptr) {
- return elementType.fromWireType(staticGetter(ptr, HEAP32[getter >> 2]));
- },
- write: function(ptr, o) {
- var destructors = [];
- staticSetter(
- ptr,
- HEAP32[setter >> 2],
- elementType.toWireType(destructors, o));
- runDestructors(destructors);
- }
+function __embind_finalize_tuple(rawTupleType) {
+ var reg = tupleRegistrations[rawTupleType];
+ delete tupleRegistrations[rawTupleType];
+ var elements = reg.elements;
+ var elementsLength = elements.length;
+ var elementTypes = elements.map(function(elt) { return elt.getterReturnType; }).
+ concat(elements.map(function(elt) { return elt.setterArgumentType; }));
+
+ var rawConstructor = reg.rawConstructor;
+ var rawDestructor = reg.rawDestructor;
+
+ whenDependentTypesAreResolved([rawTupleType], elementTypes, function(elementTypes) {
+ elements.forEach(function(elt, i) {
+ var getterReturnType = elementTypes[i];
+ var getter = elt.getter;
+ var getterContext = elt.getterContext;
+ var setterArgumentType = elementTypes[i + elementsLength];
+ var setter = elt.setter;
+ var setterContext = elt.setterContext;
+ elt.read = function(ptr) {
+ return getterReturnType.fromWireType(getter(getterContext, ptr));
+ };
+ elt.write = function(ptr, o) {
+ var destructors = [];
+ setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o));
+ runDestructors(destructors);
+ };
+ });
+
+ return [{
+ name: reg.name,
+ fromWireType: function(ptr) {
+ var rv = new Array(elementsLength);
+ for (var i = 0; i < elementsLength; ++i) {
+ rv[i] = elements[i].read(ptr);
+ }
+ rawDestructor(ptr);
+ return rv;
+ },
+ toWireType: function(destructors, o) {
+ if (elementsLength !== o.length) {
+ throw new TypeError("Incorrect number of tuple elements");
+ }
+ var ptr = rawConstructor();
+ for (var i = 0; i < elementsLength; ++i) {
+ elements[i].write(ptr, o[i]);
+ }
+ destructors.push(rawDestructor, ptr);
+ return ptr;
+ },
+ }];
});
}
+var structRegistrations = {};
+
function __embind_register_struct(
- structType,
+ rawType,
name,
- constructor,
- destructor
+ rawConstructor,
+ rawDestructor
) {
- name = Pointer_stringify(name);
- constructor = FUNCTION_TABLE[constructor];
- destructor = FUNCTION_TABLE[destructor];
-
- typeRegistry[structType] = {
- fields: {},
- fromWireType: function(ptr) {
- var fields = this.fields;
- var rv = {};
- for (var i in fields) {
- rv[i] = fields[i].read(ptr);
- }
- destructor(ptr);
- return rv;
- },
- toWireType: function(destructors, o) {
- var fields = this.fields;
- for (var fieldName in fields) {
- if (!(fieldName in o)) {
- throw new TypeError('Missing field');
- }
- }
- var ptr = constructor();
- for (var fieldName in fields) {
- fields[fieldName].write(ptr, o[fieldName]);
- }
- destructors.push(destructor);
- destructors.push(ptr);
- return ptr;
- }
+ structRegistrations[rawType] = {
+ name: Pointer_stringify(name),
+ rawConstructor: FUNCTION_TABLE[rawConstructor],
+ rawDestructor: FUNCTION_TABLE[rawDestructor],
+ fields: [],
};
}
function __embind_register_struct_field(
structType,
fieldName,
- fieldType,
+ getterReturnType,
getter,
+ getterContext,
+ setterArgumentType,
setter,
- memberPointerSize,
- memberPointer
+ setterContext
) {
- structType = requireRegisteredType(structType, 'struct');
- fieldName = Pointer_stringify(fieldName);
- fieldType = requireRegisteredType(fieldType, 'field "' + structType.name + '.' + fieldName + '"');
- getter = FUNCTION_TABLE[getter];
- setter = FUNCTION_TABLE[setter];
- memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
+ structRegistrations[structType].fields.push({
+ fieldName: Pointer_stringify(fieldName),
+ getterReturnType: getterReturnType,
+ getter: FUNCTION_TABLE[getter],
+ getterContext: getterContext,
+ setterArgumentType: setterArgumentType,
+ setter: FUNCTION_TABLE[setter],
+ setterContext: setterContext,
+ });
+}
+
+function __embind_finalize_struct(structType) {
+ var reg = structRegistrations[structType];
+ delete structRegistrations[structType];
+
+ var rawConstructor = reg.rawConstructor;
+ var rawDestructor = reg.rawDestructor;
+ var fieldRecords = reg.fields;
+ var fieldTypes = fieldRecords.map(function(field) { return field.getterReturnType; }).
+ concat(fieldRecords.map(function(field) { return field.setterArgumentType; }));
+ whenDependentTypesAreResolved([structType], fieldTypes, function(fieldTypes) {
+ var fields = {};
+ fieldRecords.forEach(function(field, i) {
+ var fieldName = field.fieldName;
+ var getterReturnType = fieldTypes[i];
+ var getter = field.getter;
+ var getterContext = field.getterContext;
+ var setterArgumentType = fieldTypes[i + fieldRecords.length];
+ var setter = field.setter;
+ var setterContext = field.setterContext;
+ fields[fieldName] = {
+ read: function(ptr) {
+ return getterReturnType.fromWireType(
+ getter(getterContext, ptr));
+ },
+ write: function(ptr, o) {
+ var destructors = [];
+ setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o));
+ runDestructors(destructors);
+ }
+ };
+ });
- structType.fields[fieldName] = {
- read: function(ptr) {
- return fieldType.fromWireType(getter(ptr, memberPointer));
+ return [{
+ name: reg.name,
+ fromWireType: function(ptr) {
+ var rv = {};
+ for (var i in fields) {
+ rv[i] = fields[i].read(ptr);
+ }
+ rawDestructor(ptr);
+ return rv;
+ },
+ toWireType: function(destructors, o) {
+ // todo: Here we have an opportunity for -O3 level "unsafe" optimizations:
+ // assume all fields are present without checking.
+ for (var fieldName in fields) {
+ if (!(fieldName in o)) {
+ throw new TypeError('Missing field');
+ }
+ }
+ var ptr = rawConstructor();
+ for (fieldName in fields) {
+ fields[fieldName].write(ptr, o[fieldName]);
+ }
+ destructors.push(rawDestructor, ptr);
+ return ptr;
+ },
+ }];
+ });
+}
+
+function RegisteredPointer(
+ name,
+ registeredClass,
+ isReference,
+ isConst,
+
+ // smart pointer properties
+ isSmartPointer,
+ pointeeType,
+ sharingPolicy,
+ rawGetPointee,
+ rawConstructor,
+ rawShare,
+ rawDestructor
+) {
+ this.name = name;
+ this.registeredClass = registeredClass;
+ this.isReference = isReference;
+ this.isConst = isConst;
+
+ // smart pointer properties
+ this.isSmartPointer = isSmartPointer;
+ this.pointeeType = pointeeType;
+ this.sharingPolicy = sharingPolicy;
+ this.rawGetPointee = rawGetPointee;
+ this.rawConstructor = rawConstructor;
+ this.rawShare = rawShare;
+ this.rawDestructor = rawDestructor;
+}
+
+RegisteredPointer.prototype.toWireType = function(destructors, handle) {
+ var self = this;
+ function throwCannotConvert() {
+ var name;
+ if (handle.$$.smartPtrType) {
+ name = handle.$$.smartPtrType.name;
+ } else {
+ name = handle.$$.ptrType.name;
+ }
+ throwBindingError('Cannot convert argument of type ' + name + ' to parameter type ' + self.name);
+ }
+
+ if (handle === null) {
+ if (this.isReference) {
+ throwBindingError('null is not a valid ' + this.name);
+ }
+
+ if (this.isSmartPointer) {
+ var ptr = this.rawConstructor();
+ destructors.push(this.rawDestructor, ptr);
+ return ptr;
+ } else {
+ return 0;
+ }
+ }
+ if (!(handle instanceof this.registeredClass.constructor)) {
+ throwBindingError('Expected null or instance of ' + this.name + ', got ' + _embind_repr(handle));
+ }
+ // TODO: this is not strictly true
+ // We could support BY_EMVAL conversions from raw pointers to smart pointers
+ // because the smart pointer can hold a