summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc25
-rwxr-xr-xemcmake8
-rw-r--r--emcmake.bat2
-rw-r--r--src/embind/embind.js154
-rw-r--r--src/embind/emval.js156
-rw-r--r--src/library.js3
-rw-r--r--src/library_glfw.js231
-rw-r--r--src/runtime.js8
-rw-r--r--system/include/emscripten/bind.h15
-rw-r--r--system/include/emscripten/emscripten.h5
-rw-r--r--system/include/emscripten/val.h200
-rw-r--r--system/include/emscripten/wire.h2
-rw-r--r--system/lib/embind/bind.cpp41
-rw-r--r--tests/cases/fixablebadcasts_fastcomp.ll27
-rw-r--r--tests/cases/fixablebadcasts_fastcomp.txt1
-rw-r--r--tests/cases/returnnan_fastcomp.ll34
-rw-r--r--tests/cases/returnnan_fastcomp.txt3
-rw-r--r--tests/core/test_inlinejs3.in1
-rw-r--r--tests/core/test_inlinejs3.out1
-rw-r--r--tests/dirent/test_readdir_empty.c47
-rw-r--r--tests/embind/embind.test.js76
-rw-r--r--tests/embind/embind_test.cpp59
-rw-r--r--tests/fs/test_idbfs_sync.c26
-rw-r--r--tests/hello_world.ll9
-rw-r--r--tests/test_core.py4
-rw-r--r--tests/test_other.py16
-rw-r--r--tools/shared.py48
28 files changed, 873 insertions, 330 deletions
diff --git a/AUTHORS b/AUTHORS
index d86070fe..99703f93 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -133,4 +133,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Jonathan Jarri <noxalus@gmail.com>
* Daniele Di Proietto <daniele.di.proietto@gmail.com>
* Dan Dascalescu <dNOSPAMdascalescu@gmail.com>
+* Thomas Borsos <thomasborsos@gmail.com>
diff --git a/emcc b/emcc
index fa51e57f..c8e1814b 100755
--- a/emcc
+++ b/emcc
@@ -522,6 +522,8 @@ Options that are modified or new in %s include:
will by default generate an output name 'dir/a.o',
but this cmdline param can be passed to generate a
file with a custom suffix 'dir/a.ext'.
+ --valid_abspath path Whitelist an absolute path to prevent warnings about
+ absolute include paths.
The target file, if specified (-o <target>), defines what will
be generated:
@@ -757,6 +759,15 @@ else:
def in_temp(name):
return os.path.join(temp_dir, os.path.basename(name))
+def in_directory(root, child):
+ # make both path absolute
+ root = os.path.realpath(root)
+ child = os.path.realpath(child)
+
+ # return true, if the common prefix of both is equal to directory
+ # e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b
+ return os.path.commonprefix([root, child]) == root
+
# Parses the essential suffix of a filename, discarding Unix-style version numbers in the name. For example for 'libz.so.1.2.8' returns '.so'
def filename_type_suffix(filename):
for i in reversed(filename.split('.')[1:]):
@@ -811,6 +822,14 @@ try:
no_heap_copy = False
proxy_to_worker = False
default_object_extension = '.o'
+ valid_abspaths = []
+
+ def is_valid_abspath(path_name):
+ for valid_abspath in valid_abspaths:
+ if in_directory(valid_abspath, path_name):
+ return True
+ return False
+
if use_cxx:
default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline.
@@ -1014,9 +1033,13 @@ try:
elif newargs[i] == '--proxy-to-worker':
proxy_to_worker = True
newargs[i] = ''
+ elif newargs[i] == '--valid-abspath':
+ valid_abspaths.append(newargs[i+1])
+ newargs[i] = ''
+ newargs[i+1] = ''
elif newargs[i].startswith(('-I', '-L')):
path_name = newargs[i][2:]
- if not absolute_warning_shown and os.path.isabs(path_name):
+ if not absolute_warning_shown and os.path.isabs(path_name) and not is_valid_abspath(path_name):
logging.warning('-I or -L of an absolute path "' + newargs[i] + '" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript). Pass \'-Wno-warn-absolute-paths\' to emcc to hide this warning.') # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not
absolute_warning_shown = True
elif newargs[i] == '--emrun':
diff --git a/emcmake b/emcmake
new file mode 100755
index 00000000..9617ace5
--- /dev/null
+++ b/emcmake
@@ -0,0 +1,8 @@
+#!/usr/bin/env python2
+
+import os, subprocess, sys
+from tools import shared
+
+configure_path = shared.path_from_root('emconfigure')
+exit(subprocess.call([configure_path] + sys.argv[1:]))
+
diff --git a/emcmake.bat b/emcmake.bat
new file mode 100644
index 00000000..c05ba028
--- /dev/null
+++ b/emcmake.bat
@@ -0,0 +1,2 @@
+@echo off
+python "%~dp0\emcmake" %*
diff --git a/src/embind/embind.js b/src/embind/embind.js
index f0cd0c74..6ec07cd9 100644
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -1,6 +1,6 @@
/*global Module*/
/*global _malloc, _free, _memcpy*/
-/*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32*/
+/*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64*/
/*global readLatin1String*/
/*global __emval_register, _emval_handle_array, __emval_decref*/
/*global ___getTypeName*/
@@ -35,7 +35,7 @@ function throwUnboundTypeError(message, types) {
seen[type] = true;
}
types.forEach(visit);
-
+
throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', ']));
}
@@ -55,7 +55,7 @@ function ensureOverloadTable(proto, methodName, humanName) {
// 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
@@ -72,7 +72,7 @@ function exposePublicSymbol(name, value, numArguments) {
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);
@@ -164,6 +164,10 @@ var typeDependencies = {};
var registeredPointers = {};
function registerType(rawType, registeredInstance) {
+ if (!('argPackAdvance' in registeredInstance)) {
+ throw new TypeError('registerType registeredInstance requires argPackAdvance');
+ }
+
var name = registeredInstance.name;
if (!rawType) {
throwBindingError('type "' + name + '" must have a positive integer typeid pointer');
@@ -268,6 +272,7 @@ function __embind_register_void(rawType, name) {
name = readLatin1String(name);
registerType(rawType, {
name: name,
+ 'argPackAdvance': 0,
'fromWireType': function() {
return undefined;
},
@@ -278,7 +283,9 @@ function __embind_register_void(rawType, name) {
});
}
-function __embind_register_bool(rawType, name, trueValue, falseValue) {
+function __embind_register_bool(rawType, name, size, trueValue, falseValue) {
+ var shift = getShiftFromSize(size);
+
name = readLatin1String(name);
registerType(rawType, {
name: name,
@@ -290,21 +297,80 @@ function __embind_register_bool(rawType, name, trueValue, falseValue) {
'toWireType': function(destructors, o) {
return o ? trueValue : falseValue;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': function(pointer) {
+ // TODO: if heap is fixed (like in asm.js) this could be executed outside
+ var heap;
+ if (size === 1) {
+ heap = HEAP8;
+ } else if (size === 2) {
+ heap = HEAP16;
+ } else if (size === 4) {
+ heap = HEAP32;
+ } else {
+ throw new TypeError("Unknown boolean type size: " + name);
+ }
+ return this['fromWireType'](heap[pointer >> shift]);
+ },
destructorFunction: null, // This type does not need a destructor
});
}
+function getShiftFromSize(size) {
+ switch (size) {
+ case 1: return 0;
+ case 2: return 1;
+ case 4: return 2;
+ case 8: return 3;
+ default:
+ throw new TypeError('Unknown type size: ' + size);
+ }
+}
+
+function integerReadValueFromPointer(name, shift, signed) {
+ switch (shift) {
+ case 0: return function(pointer) {
+ var heap = signed ? HEAP8 : HEAPU8;
+ return this['fromWireType'](heap[pointer]);
+ };
+ case 1: return function(pointer) {
+ var heap = signed ? HEAP16 : HEAPU16;
+ return this['fromWireType'](heap[pointer >> 1]);
+ };
+ case 2: return function(pointer) {
+ var heap = signed ? HEAP32 : HEAPU32;
+ return this['fromWireType'](heap[pointer >> 2]);
+ };
+ default:
+ throw new TypeError("Unknown integer type: " + name);
+ }
+}
+
+function floatReadValueFromPointer(name, shift) {
+ switch (shift) {
+ case 2: return function(pointer) {
+ return this['fromWireType'](HEAPF32[pointer >> 2]);
+ };
+ case 3: return function(pointer) {
+ return this['fromWireType'](HEAPF64[pointer >> 3]);
+ };
+ default:
+ throw new TypeError("Unknown float type: " + 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) {
+function __embind_register_integer(primitiveType, name, size, minRange, maxRange) {
name = readLatin1String(name);
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;
}
+
+ var shift = getShiftFromSize(size);
+
registerType(primitiveType, {
name: name,
- minRange: minRange,
- maxRange: maxRange,
'fromWireType': function(value) {
return value;
},
@@ -319,11 +385,16 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) {
}
return value | 0;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': integerReadValueFromPointer(name, shift, minRange !== 0),
destructorFunction: null, // This type does not need a destructor
});
}
-function __embind_register_float(rawType, name) {
+
+
+function __embind_register_float(rawType, name, size) {
+ var shift = getShiftFromSize(size);
name = readLatin1String(name);
registerType(rawType, {
name: name,
@@ -338,10 +409,17 @@ function __embind_register_float(rawType, name) {
}
return value;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': floatReadValueFromPointer(name, shift),
destructorFunction: null, // This type does not need a destructor
});
}
+// For types whose wire types are 32-bit pointers.
+function simpleReadValueFromPointer(pointer) {
+ return this['fromWireType'](HEAPU32[pointer >> 2]);
+}
+
function __embind_register_std_string(rawType, name) {
name = readLatin1String(name);
registerType(rawType, {
@@ -394,6 +472,8 @@ function __embind_register_std_string(rawType, name) {
}
return ptr;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': simpleReadValueFromPointer,
destructorFunction: function(ptr) { _free(ptr); },
});
}
@@ -434,6 +514,8 @@ function __embind_register_std_wstring(rawType, charSize, name) {
}
return ptr;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': simpleReadValueFromPointer,
destructorFunction: function(ptr) { _free(ptr); },
});
}
@@ -450,6 +532,8 @@ function __embind_register_emval(rawType, name) {
'toWireType': function(destructors, value) {
return __emval_register(value);
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': simpleReadValueFromPointer,
destructorFunction: null, // This type does not need a destructor
});
}
@@ -463,7 +547,7 @@ function __embind_register_memory_view(rawType, name) {
Int32Array,
Uint32Array,
Float32Array,
- Float64Array,
+ Float64Array,
];
name = readLatin1String(name);
@@ -476,6 +560,10 @@ function __embind_register_memory_view(rawType, name) {
var TA = typeMapping[type];
return new TA(HEAP8.buffer, data, size);
},
+ 'argPackAdvance': 16,
+ 'readValueFromPointer': function(ptr) {
+ return this['fromWireType'](ptr);
+ },
});
}
@@ -531,7 +619,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp
if (argCount < 2) {
throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!");
}
-
+
var isClassMethodFunc = (argTypes[1] !== null && classType !== null);
if (!isClassMethodFunc && !FUNCTION_TABLE[cppTargetFunc]) {
@@ -560,7 +648,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp
// Determine if we need to use a dynamic stack to store the destructors for the function parameters.
// TODO: Remove this completely once all function invokers are being dynamically generated.
var needsDestructorStack = false;
-
+
for(var i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here.
if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack
needsDestructorStack = true;
@@ -595,7 +683,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp
invokerFnBody +=
(returns?"var rv = ":"") + "invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";
-
+
if (needsDestructorStack) {
invokerFnBody += "runDestructors(destructors);\n";
} else {
@@ -608,7 +696,7 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp
}
}
}
-
+
if (returns) {
invokerFnBody += "return retType.fromWireType(rv);\n";
}
@@ -676,7 +764,7 @@ function __embind_finalize_value_array(rawTupleType) {
var rawConstructor = reg.rawConstructor;
var rawDestructor = reg.rawDestructor;
-
+
whenDependentTypesAreResolved([rawTupleType], elementTypes, function(elementTypes) {
elements.forEach(function(elt, i) {
var getterReturnType = elementTypes[i];
@@ -718,6 +806,8 @@ function __embind_finalize_value_array(rawTupleType) {
}
return ptr;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': simpleReadValueFromPointer,
destructorFunction: rawDestructor,
}];
});
@@ -819,6 +909,8 @@ function __embind_finalize_value_object(structType) {
}
return ptr;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': simpleReadValueFromPointer,
destructorFunction: rawDestructor,
}];
});
@@ -860,7 +952,7 @@ var genericPointerToWireType = function(destructors, handle) {
if (undefined === handle.$$.smartPtr) {
throwBindingError('Passing raw pointer to smart pointer is illegal');
}
-
+
switch (this.sharingPolicy) {
case 0: // NONE
// no upcasting
@@ -870,11 +962,11 @@ var genericPointerToWireType = function(destructors, handle) {
throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name);
}
break;
-
+
case 1: // INTRUSIVE
ptr = handle.$$.smartPtr;
break;
-
+
case 2: // BY_EMVAL
if (handle.$$.smartPtrType === this) {
ptr = handle.$$.smartPtr;
@@ -891,7 +983,7 @@ var genericPointerToWireType = function(destructors, handle) {
}
}
break;
-
+
default:
throwBindingError('Unsupporting sharing policy');
}
@@ -985,7 +1077,7 @@ function RegisteredPointer(
this['toWireType'] = genericPointerToWireType;
// Here we must leave this.destructorFunction undefined, since whether genericPointerToWireType returns
// a pointer that needs to be freed up is runtime-dependent, and cannot be evaluated at registration time.
- // TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in
+ // TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in
// craftInvokerFunction altogether.
}
}
@@ -1003,6 +1095,9 @@ RegisteredPointer.prototype.destructor = function(ptr) {
}
};
+RegisteredPointer.prototype['argPackAdvance'] = 8;
+RegisteredPointer.prototype['readValueFromPointer'] = simpleReadValueFromPointer;
+
RegisteredPointer.prototype['fromWireType'] = function(ptr) {
// ptr is a raw pointer (or a raw smartpointer)
@@ -1110,7 +1205,7 @@ ClassHandle.prototype['isAliasOf'] = function(other) {
right = rightClass.upcast(right);
rightClass = rightClass.baseClass;
}
-
+
return leftClass === rightClass && left === right;
};
@@ -1195,7 +1290,7 @@ Module['setDelayFunction'] = function setDelayFunction(fn) {
delayFunction(flushPendingDeletes);
}
};
-
+
function RegisteredClass(
name,
constructor,
@@ -1298,7 +1393,7 @@ function __embind_register_class(
true,
false,
false);
-
+
var pointerConverter = new RegisteredPointer(
name + '*',
registeredClass,
@@ -1360,10 +1455,10 @@ function __embind_register_class_constructor(
for (var i = 1; i < argCount; ++i) {
args[i] = argTypes[i]['toWireType'](destructors, arguments[i - 1]);
}
-
+
var ptr = invoker.apply(null, args);
runDestructors(destructors);
-
+
return argTypes[0]['fromWireType'](ptr);
};
return [];
@@ -1447,7 +1542,7 @@ function __embind_register_class_function(
}
whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
-
+
var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context);
// Replace the initial unbound-handler-stub function with the appropriate member function, now that all types
@@ -1627,8 +1722,11 @@ function __embind_register_smart_ptr(
function __embind_register_enum(
rawType,
- name
+ name,
+ size,
+ isSigned
) {
+ var shift = getShiftFromSize(size);
name = readLatin1String(name);
function constructor() {
@@ -1644,6 +1742,8 @@ function __embind_register_enum(
'toWireType': function(destructors, c) {
return c.value;
},
+ 'argPackAdvance': 8,
+ 'readValueFromPointer': integerReadValueFromPointer(name, shift, isSigned),
destructorFunction: null,
});
exposePublicSymbol(name, constructor);
diff --git a/src/embind/emval.js b/src/embind/emval.js
index 039f1d61..4007701a 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -55,6 +55,7 @@ function requireHandle(handle) {
if (!handle) {
throwBindingError('Cannot use deleted val. handle = ' + handle);
}
+ return _emval_handle_array[handle].value;
}
function __emval_register(value) {
@@ -105,9 +106,9 @@ function __emval_new_cstring(v) {
return __emval_register(getStringOrSymbol(v));
}
-function __emval_take_value(type, v) {
+function __emval_take_value(type, argv) {
type = requireRegisteredType(type, '_emval_take_value');
- v = type['fromWireType'](v);
+ var v = type['readValueFromPointer'](argv);
return __emval_register(v);
}
@@ -116,70 +117,51 @@ 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) {
+ function emval_allocator_3(constructor, argTypes, args) {
var argType0 = requireRegisteredType(HEAP32[(argTypes >> 2)], "parameter 0");
- var arg0 = argType0.fromWireType(arg0Wired);
+ var arg0 = argType0.readValueFromPointer(args);
var argType1 = requireRegisteredType(HEAP32[(argTypes >> 2) + 1], "parameter 1");
- var arg1 = argType1.fromWireType(arg1Wired);
+ var arg1 = argType1.readValueFromPointer(args + 8);
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 arg2 = argType2.readValueFromPointer(args + 16);
+ var obj = new constructor(arg0, arg1, arg2);
+ return __emval_register(obj);
} */
- 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";
+ var functionBody =
+ "return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n";
for(var i = 0; i < argCount; ++i) {
- invokerFnBody +=
+ functionBody +=
"var argType"+i+" = requireRegisteredType(HEAP32[(argTypes >> 2) + "+i+"], \"parameter "+i+"\");\n" +
- "var arg"+i+" = argType"+i+".fromWireType(arg"+i+"Wired);\n";
+ "var arg"+i+" = argType"+i+".readValueFromPointer(args);\n" +
+ "args += argType"+i+".argPackAdvance;\n";
}
- invokerFnBody +=
- "var constructor = _emval_handle_array[handle].value;\n" +
+ functionBody +=
"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;
+ /*jshint evil:true*/
+ return (new Function("requireRegisteredType", "HEAP32", "__emval_register", functionBody))(
+ requireRegisteredType, HEAP32, __emval_register);
}
-function __emval_new(handle, argCount, argTypes) {
- requireHandle(handle);
-
+function __emval_new(handle, argCount, argTypes, args) {
+ handle = 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));
- }
+ return newer(handle, argTypes, args);
}
// appease jshint (technically this code uses eval)
@@ -196,46 +178,39 @@ function __emval_get_module_property(name) {
}
function __emval_get_property(handle, key) {
- requireHandle(handle);
- return __emval_register(_emval_handle_array[handle].value[_emval_handle_array[key].value]);
+ handle = requireHandle(handle);
+ key = requireHandle(key);
+ return __emval_register(handle[key]);
}
function __emval_set_property(handle, key, value) {
- requireHandle(handle);
- _emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value;
+ handle = requireHandle(handle);
+ key = requireHandle(key);
+ value = requireHandle(value);
+ handle[key] = value;
}
function __emval_as(handle, returnType, destructorsRef) {
- requireHandle(handle);
+ handle = requireHandle(handle);
returnType = requireRegisteredType(returnType, 'emval::as');
var destructors = [];
var rd = __emval_register(destructors);
HEAP32[destructorsRef >> 2] = rd;
- return returnType['toWireType'](destructors, _emval_handle_array[handle].value);
+ return returnType['toWireType'](destructors, handle);
}
-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'](argWireTypes[i]);
- }
- return a;
-}
-
-function __emval_call(handle, argCount, argTypes) {
- requireHandle(handle);
+function __emval_call(handle, argCount, argTypes, argv) {
+ handle = 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 type = types[i];
+ args[i] = type['readValueFromPointer'](argv);
+ argv += type.argPackAdvance;
}
- var fn = _emval_handle_array[handle].value;
- var rv = fn.apply(undefined, args);
+ var rv = handle.apply(undefined, args);
return __emval_register(rv);
}
@@ -255,44 +230,59 @@ function allocateDestructors(destructorsRef) {
return destructors;
}
+// Leave id 0 undefined. It's not a big deal, but might be confusing
+// to have null be a valid method caller.
+var methodCallers = [undefined];
+
+function addMethodCaller(caller) {
+ var id = methodCallers.length;
+ methodCallers.push(caller);
+ return id;
+}
+
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 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType", "allocateDestructors"];
- var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType, allocateDestructors];
+ var params = ["retType"];
+ var args = [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]);
+ params.push("argType" + i);
+ args.push(types[1 + i]);
}
- var invokerFnBody =
- "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name, destructorsRef" + argsListWired + ") {\n" +
- " requireHandle(handle);\n" +
- " name = getStringOrSymbol(name);\n";
+ var functionBody =
+ "return function (handle, name, destructors, args) {\n";
for (var i = 0; i < argCount - 1; ++i) {
- invokerFnBody += " var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n";
+ functionBody +=
+ " var arg" + i + " = argType" + i + ".readValueFromPointer(args);\n" +
+ " args += argType" + i + ".argPackAdvance;\n";
}
- invokerFnBody +=
- " var obj = _emval_handle_array[handle].value;\n" +
- " var rv = obj[name](" + argsList + ");\n" +
- " return retType.toWireType(allocateDestructors(destructorsRef), rv);\n" +
- "}));\n";
-
- args1.push(invokerFnBody);
- var invokerFunction = new_(Function, args1).apply(null, args2);
- return invokerFunction;
+ functionBody +=
+ " var rv = handle[name](" + argsList + ");\n" +
+ " return retType.toWireType(destructors, rv);\n" +
+ "};\n";
+
+ params.push(functionBody);
+ var invokerFunction = new_(Function, params).apply(null, args);
+ return addMethodCaller(createNamedFunction(signatureName, invokerFunction));
+}
+
+function __emval_call_method(caller, handle, methodName, destructorsRef, args) {
+ caller = methodCallers[caller];
+ handle = requireHandle(handle);
+ methodName = getStringOrSymbol(methodName);
+ return caller(handle, methodName, allocateDestructors(destructorsRef), args);
}
function __emval_has_function(handle, name) {
+ handle = requireHandle(handle);
name = getStringOrSymbol(name);
- return _emval_handle_array[handle].value[name] instanceof Function;
+ return handle[name] instanceof Function;
}
diff --git a/src/library.js b/src/library.js
index 935d07e6..6c2bfa36 100644
--- a/src/library.js
+++ b/src/library.js
@@ -325,6 +325,9 @@ LibraryManager.library = {
// int mkdir(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
path = Pointer_stringify(path);
+ // remove a trailing slash, if one - /a/b/ has basename of '', but
+ // we want to create b in the context of this function
+ if (path[path.length-1] === '/') path = path.substr(0, path.length-1);
try {
FS.mkdir(path, mode, 0);
return 0;
diff --git a/src/library_glfw.js b/src/library_glfw.js
index e5782900..f72aeb24 100644
--- a/src/library_glfw.js
+++ b/src/library_glfw.js
@@ -18,6 +18,7 @@
*
* Authors:
* - Éloi Rivard <eloi.rivard@gmail.com>
+ * - Thomas Borsos <thomasborsos@gmail.com>
*
******************************************************************************/
@@ -50,58 +51,60 @@ var LibraryGLFW = {
DOMToGLFWKeyCode: function(keycode) {
switch (keycode) {
- case 0x09: return 295 ; //DOM_VK_TAB -> GLFW_KEY_TAB
- case 0x1B: return 257 ; //DOM_VK_ESCAPE -> GLFW_KEY_ESC
- case 0x6A: return 313 ; //DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY
- case 0x6B: return 315 ; //DOM_VK_ADD -> GLFW_KEY_KP_ADD
- case 0x6D: return 314 ; //DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT
- case 0x6E: return 316 ; //DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL
- case 0x6F: return 312 ; //DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE
- case 0x70: return 258 ; //DOM_VK_F1 -> GLFW_KEY_F1
- case 0x71: return 259 ; //DOM_VK_F2 -> GLFW_KEY_F2
- case 0x72: return 260 ; //DOM_VK_F3 -> GLFW_KEY_F3
- case 0x73: return 261 ; //DOM_VK_F4 -> GLFW_KEY_F4
- case 0x74: return 262 ; //DOM_VK_F5 -> GLFW_KEY_F5
- case 0x75: return 263 ; //DOM_VK_F6 -> GLFW_KEY_F6
- case 0x76: return 264 ; //DOM_VK_F7 -> GLFW_KEY_F7
- case 0x77: return 265 ; //DOM_VK_F8 -> GLFW_KEY_F8
- case 0x78: return 266 ; //DOM_VK_F9 -> GLFW_KEY_F9
- case 0x79: return 267 ; //DOM_VK_F10 -> GLFW_KEY_F10
- case 0x7a: return 268 ; //DOM_VK_F11 -> GLFW_KEY_F11
- case 0x7b: return 269 ; //DOM_VK_F12 -> GLFW_KEY_F12
- case 0x25: return 285 ; //DOM_VK_LEFT -> GLFW_KEY_LEFT
- case 0x26: return 283 ; //DOM_VK_UP -> GLFW_KEY_UP
- case 0x27: return 286 ; //DOM_VK_RIGHT -> GLFW_KEY_RIGHT
- case 0x28: return 284 ; //DOM_VK_DOWN -> GLFW_KEY_DOWN
- case 0x21: return 298 ; //DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP
- case 0x22: return 299 ; //DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN
- case 0x24: return 300 ; //DOM_VK_HOME -> GLFW_KEY_HOME
- case 0x23: return 301 ; //DOM_VK_END -> GLFW_KEY_END
- case 0x2d: return 296 ; //DOM_VK_INSERT -> GLFW_KEY_INSERT
- case 16 : return 287 ; //DOM_VK_SHIFT -> GLFW_KEY_LSHIFT
- case 0x05: return 287 ; //DOM_VK_LEFT_SHIFT -> GLFW_KEY_LSHIFT
- case 0x06: return 288 ; //DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT
- case 17 : return 289 ; //DOM_VK_CONTROL -> GLFW_KEY_LCTRL
- case 0x03: return 289 ; //DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL
- case 0x04: return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL
- case 18 : return 291 ; //DOM_VK_ALT -> GLFW_KEY_LALT
- case 0x02: return 291 ; //DOM_VK_LEFT_ALT -> GLFW_KEY_LALT
- case 0x01: return 292 ; //DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT
- case 96 : return 302 ; //GLFW_KEY_KP_0
- case 97 : return 303 ; //GLFW_KEY_KP_1
- case 98 : return 304 ; //GLFW_KEY_KP_2
- case 99 : return 305 ; //GLFW_KEY_KP_3
- case 100 : return 306 ; //GLFW_KEY_KP_4
- case 101 : return 307 ; //GLFW_KEY_KP_5
- case 102 : return 308 ; //GLFW_KEY_KP_6
- case 103 : return 309 ; //GLFW_KEY_KP_7
- case 104 : return 310 ; //GLFW_KEY_KP_8
- case 105 : return 311 ; //GLFW_KEY_KP_9
+ case 0x08: return 295 ; // DOM_VK_BACKSPACE -> GLFW_KEY_BACKSPACE
+ case 0x09: return 293 ; // DOM_VK_TAB -> GLFW_KEY_TAB
+ case 0x0D: return 294 ; // DOM_VK_ENTER -> GLFW_KEY_ENTER
+ case 0x1B: return 257 ; // DOM_VK_ESCAPE -> GLFW_KEY_ESC
+ case 0x6A: return 313 ; // DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY
+ case 0x6B: return 315 ; // DOM_VK_ADD -> GLFW_KEY_KP_ADD
+ case 0x6D: return 314 ; // DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT
+ case 0x6E: return 316 ; // DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL
+ case 0x6F: return 312 ; // DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE
+ case 0x70: return 258 ; // DOM_VK_F1 -> GLFW_KEY_F1
+ case 0x71: return 259 ; // DOM_VK_F2 -> GLFW_KEY_F2
+ case 0x72: return 260 ; // DOM_VK_F3 -> GLFW_KEY_F3
+ case 0x73: return 261 ; // DOM_VK_F4 -> GLFW_KEY_F4
+ case 0x74: return 262 ; // DOM_VK_F5 -> GLFW_KEY_F5
+ case 0x75: return 263 ; // DOM_VK_F6 -> GLFW_KEY_F6
+ case 0x76: return 264 ; // DOM_VK_F7 -> GLFW_KEY_F7
+ case 0x77: return 265 ; // DOM_VK_F8 -> GLFW_KEY_F8
+ case 0x78: return 266 ; // DOM_VK_F9 -> GLFW_KEY_F9
+ case 0x79: return 267 ; // DOM_VK_F10 -> GLFW_KEY_F10
+ case 0x7a: return 268 ; // DOM_VK_F11 -> GLFW_KEY_F11
+ case 0x7b: return 269 ; // DOM_VK_F12 -> GLFW_KEY_F12
+ case 0x25: return 285 ; // DOM_VK_LEFT -> GLFW_KEY_LEFT
+ case 0x26: return 283 ; // DOM_VK_UP -> GLFW_KEY_UP
+ case 0x27: return 286 ; // DOM_VK_RIGHT -> GLFW_KEY_RIGHT
+ case 0x28: return 284 ; // DOM_VK_DOWN -> GLFW_KEY_DOWN
+ case 0x21: return 298 ; // DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP
+ case 0x22: return 299 ; // DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN
+ case 0x24: return 300 ; // DOM_VK_HOME -> GLFW_KEY_HOME
+ case 0x23: return 301 ; // DOM_VK_END -> GLFW_KEY_END
+ case 0x2d: return 296 ; // DOM_VK_INSERT -> GLFW_KEY_INSERT
+ case 16 : return 287 ; // DOM_VK_SHIFT -> GLFW_KEY_LSHIFT
+ case 0x05: return 287 ; // DOM_VK_LEFT_SHIFT -> GLFW_KEY_LSHIFT
+ case 0x06: return 288 ; // DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT
+ case 17 : return 289 ; // DOM_VK_CONTROL -> GLFW_KEY_LCTRL
+ case 0x03: return 289 ; // DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL
+ case 0x04: return 290 ; // DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL
+ case 18 : return 291 ; // DOM_VK_ALT -> GLFW_KEY_LALT
+ case 0x02: return 291 ; // DOM_VK_LEFT_ALT -> GLFW_KEY_LALT
+ case 0x01: return 292 ; // DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT
+ case 96 : return 302 ; // GLFW_KEY_KP_0
+ case 97 : return 303 ; // GLFW_KEY_KP_1
+ case 98 : return 304 ; // GLFW_KEY_KP_2
+ case 99 : return 305 ; // GLFW_KEY_KP_3
+ case 100 : return 306 ; // GLFW_KEY_KP_4
+ case 101 : return 307 ; // GLFW_KEY_KP_5
+ case 102 : return 308 ; // GLFW_KEY_KP_6
+ case 103 : return 309 ; // GLFW_KEY_KP_7
+ case 104 : return 310 ; // GLFW_KEY_KP_8
+ case 105 : return 311 ; // GLFW_KEY_KP_9
default : return keycode;
};
},
- //UCS-2 to UTF16 (ISO 10646)
+ // UCS-2 to UTF16 (ISO 10646)
getUnicodeChar: function(value) {
var output = '';
if (value > 0xFFFF) {
@@ -114,7 +117,7 @@ var LibraryGLFW = {
},
onKeyPress: function(event) {
- //charCode is only available whith onKeyPress event
+ // charCode is only available whith onKeyPress event
var char = GLFW.getUnicodeChar(event.charCode);
if (event.charCode) {
@@ -134,7 +137,7 @@ var LibraryGLFW = {
},
onKeydown: function(event) {
- GLFW.onKeyChanged(event, 1);//GLFW_PRESS
+ GLFW.onKeyChanged(event, 1);// GLFW_PRESS
// This logic comes directly from the sdl implementation. We cannot
// call preventDefault on all keydown events otherwise onKeyPress will
// not get called
@@ -144,7 +147,7 @@ var LibraryGLFW = {
},
onKeyup: function(event) {
- GLFW.onKeyChanged(event, 0);//GLFW_RELEASE
+ GLFW.onKeyChanged(event, 0);// GLFW_RELEASE
},
onMousemove: function(event) {
@@ -175,25 +178,34 @@ var LibraryGLFW = {
return;
}
- if (status == 1) {//GLFW_PRESS
+ if (status == 1) {// GLFW_PRESS
try {
event.target.setCapture();
} catch (e) {}
}
event.preventDefault();
- //DOM and glfw have the same button codes
- Runtime.dynCall('vii', GLFW.mouseButtonFunc, [event['button'], status]);
+
+ // DOM and glfw have different button codes
+ var eventButton = event['button'];
+ if (eventButton > 0) {
+ if (eventButton == 1) {
+ eventButton = 2;
+ } else {
+ eventButton = 1;
+ }
+ }
+ Runtime.dynCall('vii', GLFW.mouseButtonFunc, [eventButton, status]);
},
onMouseButtonDown: function(event) {
GLFW.buttons |= (1 << event['button']);
- GLFW.onMouseButtonChanged(event, 1);//GLFW_PRESS
+ GLFW.onMouseButtonChanged(event, 1);// GLFW_PRESS
},
onMouseButtonUp: function(event) {
GLFW.buttons &= ~(1 << event['button']);
- GLFW.onMouseButtonChanged(event, 0);//GLFW_RELEASE
+ GLFW.onMouseButtonChanged(event, 0);// GLFW_RELEASE
},
onMouseWheel: function(event) {
@@ -213,8 +225,7 @@ var LibraryGLFW = {
if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
width = screen["width"];
height = screen["height"];
- }
- else {
+ } else {
width = GLFW.windowWidth;
height = GLFW.windowHeight;
// TODO set position
@@ -279,40 +290,40 @@ var LibraryGLFW = {
//TODO: Init with correct values
GLFW.params = new Array();
- GLFW.params[0x00030001] = true; //GLFW_MOUSE_CURSOR
- GLFW.params[0x00030002] = false; //GLFW_STICKY_KEYS
- GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS
- GLFW.params[0x00030004] = false; //GLFW_SYSTEM_KEYS
- GLFW.params[0x00030005] = false; //GLFW_KEY_REPEAT
- GLFW.params[0x00030006] = true; //GLFW_AUTO_POLL_EVENTS
- GLFW.params[0x00020001] = true; //GLFW_OPENED
- GLFW.params[0x00020002] = true; //GLFW_ACTIVE
- GLFW.params[0x00020003] = false; //GLFW_ICONIFIED
- GLFW.params[0x00020004] = true; //GLFW_ACCELERATED
- GLFW.params[0x00020005] = 0; //GLFW_RED_BITS
- GLFW.params[0x00020006] = 0; //GLFW_GREEN_BITS
- GLFW.params[0x00020007] = 0; //GLFW_BLUE_BITS
- GLFW.params[0x00020008] = 0; //GLFW_ALPHA_BITS
- GLFW.params[0x00020009] = 0; //GLFW_DEPTH_BITS
- GLFW.params[0x0002000A] = 0; //GLFW_STENCIL_BITS
- GLFW.params[0x0002000B] = 0; //GLFW_REFRESH_RATE
- GLFW.params[0x0002000C] = 0; //GLFW_ACCUM_RED_BITS
- GLFW.params[0x0002000D] = 0; //GLFW_ACCUM_GREEN_BITS
- GLFW.params[0x0002000E] = 0; //GLFW_ACCUM_BLUE_BITS
- GLFW.params[0x0002000F] = 0; //GLFW_ACCUM_ALPHA_BITS
- GLFW.params[0x00020010] = 0; //GLFW_AUX_BUFFERS
- GLFW.params[0x00020011] = 0; //GLFW_STEREO
- GLFW.params[0x00020012] = 0; //GLFW_WINDOW_NO_RESIZE
- GLFW.params[0x00020013] = 0; //GLFW_FSAA_SAMPLES
- GLFW.params[0x00020014] = 0; //GLFW_OPENGL_VERSION_MAJOR
- GLFW.params[0x00020015] = 0; //GLFW_OPENGL_VERSION_MINOR
- GLFW.params[0x00020016] = 0; //GLFW_OPENGL_FORWARD_COMPAT
- GLFW.params[0x00020017] = 0; //GLFW_OPENGL_DEBUG_CONTEXT
- GLFW.params[0x00020018] = 0; //GLFW_OPENGL_PROFILE
+ GLFW.params[0x00030001] = true; // GLFW_MOUSE_CURSOR
+ GLFW.params[0x00030002] = false; // GLFW_STICKY_KEYS
+ GLFW.params[0x00030003] = true; // GLFW_STICKY_MOUSE_BUTTONS
+ GLFW.params[0x00030004] = false; // GLFW_SYSTEM_KEYS
+ GLFW.params[0x00030005] = false; // GLFW_KEY_REPEAT
+ GLFW.params[0x00030006] = true; // GLFW_AUTO_POLL_EVENTS
+ GLFW.params[0x00020001] = true; // GLFW_OPENED
+ GLFW.params[0x00020002] = true; // GLFW_ACTIVE
+ GLFW.params[0x00020003] = false; // GLFW_ICONIFIED
+ GLFW.params[0x00020004] = true; // GLFW_ACCELERATED
+ GLFW.params[0x00020005] = 0; // GLFW_RED_BITS
+ GLFW.params[0x00020006] = 0; // GLFW_GREEN_BITS
+ GLFW.params[0x00020007] = 0; // GLFW_BLUE_BITS
+ GLFW.params[0x00020008] = 0; // GLFW_ALPHA_BITS
+ GLFW.params[0x00020009] = 0; // GLFW_DEPTH_BITS
+ GLFW.params[0x0002000A] = 0; // GLFW_STENCIL_BITS
+ GLFW.params[0x0002000B] = 0; // GLFW_REFRESH_RATE
+ GLFW.params[0x0002000C] = 0; // GLFW_ACCUM_RED_BITS
+ GLFW.params[0x0002000D] = 0; // GLFW_ACCUM_GREEN_BITS
+ GLFW.params[0x0002000E] = 0; // GLFW_ACCUM_BLUE_BITS
+ GLFW.params[0x0002000F] = 0; // GLFW_ACCUM_ALPHA_BITS
+ GLFW.params[0x00020010] = 0; // GLFW_AUX_BUFFERS
+ GLFW.params[0x00020011] = 0; // GLFW_STEREO
+ GLFW.params[0x00020012] = 0; // GLFW_WINDOW_NO_RESIZE
+ GLFW.params[0x00020013] = 0; // GLFW_FSAA_SAMPLES
+ GLFW.params[0x00020014] = 0; // GLFW_OPENGL_VERSION_MAJOR
+ GLFW.params[0x00020015] = 0; // GLFW_OPENGL_VERSION_MINOR
+ GLFW.params[0x00020016] = 0; // GLFW_OPENGL_FORWARD_COMPAT
+ GLFW.params[0x00020017] = 0; // GLFW_OPENGL_DEBUG_CONTEXT
+ GLFW.params[0x00020018] = 0; // GLFW_OPENGL_PROFILE
GLFW.keys = new Array();
- return 1; //GL_TRUE
+ return 1; // GL_TRUE
},
glfwTerminate: function() {},
@@ -332,33 +343,31 @@ var LibraryGLFW = {
if (width > 0 && height == 0) {
height = 3 * width / 4;
}
- GLFW.params[0x00020005] = redbits; //GLFW_RED_BITS
- GLFW.params[0x00020006] = greenbits; //GLFW_GREEN_BITS
- GLFW.params[0x00020007] = bluebits; //GLFW_BLUE_BITS
- GLFW.params[0x00020008] = alphabits; //GLFW_ALPHA_BITS
- GLFW.params[0x00020009] = depthbits; //GLFW_DEPTH_BITS
- GLFW.params[0x0002000A] = stencilbits; //GLFW_STENCIL_BITS
-
- if (mode == 0x00010001) {//GLFW_WINDOW
+ GLFW.params[0x00020005] = redbits; // GLFW_RED_BITS
+ GLFW.params[0x00020006] = greenbits; // GLFW_GREEN_BITS
+ GLFW.params[0x00020007] = bluebits; // GLFW_BLUE_BITS
+ GLFW.params[0x00020008] = alphabits; // GLFW_ALPHA_BITS
+ GLFW.params[0x00020009] = depthbits; // GLFW_DEPTH_BITS
+ GLFW.params[0x0002000A] = stencilbits; // GLFW_STENCIL_BITS
+
+ if (mode == 0x00010001) {// GLFW_WINDOW
Browser.setCanvasSize(GLFW.initWindowWidth = width,
GLFW.initWindowHeight = height);
- GLFW.params[0x00030003] = true; //GLFW_STICKY_MOUSE_BUTTONS
- }
- else if (mode == 0x00010002) {//GLFW_FULLSCREEN
+ GLFW.params[0x00030003] = true; // GLFW_STICKY_MOUSE_BUTTONS
+ } else if (mode == 0x00010002) {// GLFW_FULLSCREEN
GLFW.requestFullScreen();
- GLFW.params[0x00030003] = false; //GLFW_STICKY_MOUSE_BUTTONS
- }
- else{
+ GLFW.params[0x00030003] = false; // GLFW_STICKY_MOUSE_BUTTONS
+ } else {
throw "Invalid glfwOpenWindow mode.";
}
var contextAttributes = {
- antialias: (GLFW.params[0x00020013] > 1), //GLFW_FSAA_SAMPLES
- depth: (GLFW.params[0x00020009] > 0), //GLFW_DEPTH_BITS
- stencil: (GLFW.params[0x0002000A] > 0) //GLFW_STENCIL_BITS
+ antialias: (GLFW.params[0x00020013] > 1), // GLFW_FSAA_SAMPLES
+ depth: (GLFW.params[0x00020009] > 0), // GLFW_DEPTH_BITS
+ stencil: (GLFW.params[0x0002000A] > 0) // GLFW_STENCIL_BITS
}
Module.ctx = Browser.createContext(Module['canvas'], true, true, contextAttributes);
- return 1; //GL_TRUE
+ return 1; // GL_TRUE
},
glfwOpenWindowHint: function(target, hint) {
@@ -439,7 +448,7 @@ var LibraryGLFW = {
setValue(ypos, Browser.mouseY, 'i32');
},
- //I believe it is not possible to move the mouse with javascript
+ // I believe it is not possible to move the mouse with javascript
glfwSetMousePos: function(xpos, ypos) {},
glfwGetMouseWheel: function() {
@@ -514,7 +523,7 @@ var LibraryGLFW = {
str += 'i';
}
Runtime.dynCall(str, fun, arg);
- //One single thread
+ // One single thread
return 0;
},
@@ -523,7 +532,7 @@ var LibraryGLFW = {
glfwWaitThread: function(ID, waitmode) {},
glfwGetThreadID: function() {
- //One single thread
+ // One single thread
return 0;
},
@@ -546,7 +555,7 @@ var LibraryGLFW = {
glfwBroadcastCond: function(cond) { throw "glfwBroadcastCond is not implemented."; },
glfwGetNumberOfProcessors: function() {
- //Threads are disabled anyway…
+ // Threads are disabled anyway…
return 1;
},
diff --git a/src/runtime.js b/src/runtime.js
index edcbf637..63610d3b 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -409,7 +409,13 @@ var Runtime = {
abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
}
}
- return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+ try {
+ var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+ } catch(e) {
+ Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+ throw e;
+ }
+ return Runtime.asmConstCache[code] = evalled;
},
warnOnce: function(text) {
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index 390533f3..872f279b 100644
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -17,8 +17,6 @@ namespace emscripten {
BY_EMVAL = 2,
};
-#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline))
-
namespace internal {
typedef long GenericEnumValue;
@@ -35,18 +33,21 @@ namespace emscripten {
void _embind_register_bool(
TYPEID boolType,
const char* name,
+ size_t size,
bool trueValue,
bool falseValue);
void _embind_register_integer(
TYPEID integerType,
const char* name,
+ size_t size,
long minRange,
unsigned long maxRange);
void _embind_register_float(
TYPEID floatType,
- const char* name);
+ const char* name,
+ size_t size);
void _embind_register_std_string(
TYPEID stringType,
@@ -163,7 +164,9 @@ namespace emscripten {
void _embind_register_enum(
TYPEID enumType,
- const char* name);
+ const char* name,
+ size_t size,
+ bool isSigned);
void _embind_register_enum_value(
TYPEID enumType,
@@ -1182,7 +1185,9 @@ namespace emscripten {
enum_(const char* name) {
_embind_register_enum(
internal::TypeID<EnumType>::get(),
- name);
+ name,
+ sizeof(EnumType),
+ std::is_signed<typename std::underlying_type<EnumType>::type>::value);
}
enum_& value(const char* name, EnumType value) {
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index 2b883f93..73836018 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -42,8 +42,8 @@ extern "C" {
/*
* Input-output versions of EM_ASM.
*
- * EM_ASM_ (an extra _ is added) allows sending values (ints
- * or doubles) into the code. If you also want a return value,
+ * EM_ASM_ (an extra _ is added) or EM_ASM_ARGS allow sending values
+ * (ints or doubles) into the code. If you also want a return value,
* EM_ASM_INT receives arguments (of int or double type)
* and returns an int; EM_ASM_DOUBLE does the same and returns
* a double.
@@ -60,6 +60,7 @@ extern "C" {
* EM_ASM_INT_V and EM_ASM_DOUBLE_V respectively.
*/
#define EM_ASM_(code, ...) emscripten_asm_const_int(#code, __VA_ARGS__)
+#define EM_ASM_ARGS(code, ...) emscripten_asm_const_int(#code, __VA_ARGS__)
#define EM_ASM_INT(code, ...) emscripten_asm_const_int(#code, __VA_ARGS__)
#define EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double(#code, __VA_ARGS__)
#define EM_ASM_INT_V(code) emscripten_asm_const_int(#code)
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
index 19b1beb1..e217c959 100644
--- a/system/include/emscripten/val.h
+++ b/system/include/emscripten/val.h
@@ -2,6 +2,7 @@
#include <stdint.h> // uintptr_t
#include <emscripten/wire.h>
+#include <array>
#include <vector>
namespace emscripten {
@@ -12,12 +13,10 @@ namespace emscripten {
typedef struct _EM_VAL* EM_VAL;
typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS;
+ typedef struct _EM_METHOD_CALLER* EM_METHOD_CALLER;
+ typedef double EM_GENERIC_WIRE_TYPE;
+ typedef const void* EM_VAR_ARGS;
- // TODO: functions returning this are reinterpret_cast
- // into the correct return type. this needs some thought
- // for asm.js.
- typedef void _POLYMORPHIC_RESULT;
-
void _emval_incref(EM_VAL value);
void _emval_decref(EM_VAL value);
@@ -28,37 +27,45 @@ namespace emscripten {
EM_VAL _emval_undefined();
EM_VAL _emval_null();
EM_VAL _emval_new_cstring(const char*);
- void _emval_take_value(TYPEID type/*, ...*/);
+
+ EM_VAL _emval_take_value(TYPEID type, EM_VAR_ARGS argv);
EM_VAL _emval_new(
EM_VAL value,
unsigned argCount,
- internal::TYPEID argTypes[]
- /*, ... */);
+ internal::TYPEID argTypes[],
+ EM_VAR_ARGS argv);
EM_VAL _emval_get_global(const char* name);
EM_VAL _emval_get_module_property(const char* name);
EM_VAL _emval_get_property(EM_VAL object, EM_VAL key);
void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value);
- _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* runDestructors);
+ EM_GENERIC_WIRE_TYPE _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* destructors);
EM_VAL _emval_call(
EM_VAL value,
unsigned argCount,
- internal::TYPEID argTypes[]
- /*, ... */);
+ internal::TYPEID argTypes[],
+ EM_VAR_ARGS argv);
- // DO NOT call this more than once per signature. It will leak function pointer offsets!
- GenericFunction _emval_get_method_caller(
+ // DO NOT call this more than once per signature. It will
+ // leak generated function objects!
+ EM_METHOD_CALLER _emval_get_method_caller(
unsigned argCount, // including return value
internal::TYPEID argTypes[]);
+ EM_GENERIC_WIRE_TYPE _emval_call_method(
+ EM_METHOD_CALLER caller,
+ EM_VAL handle,
+ const char* methodName,
+ EM_DESTRUCTORS* destructors,
+ EM_VAR_ARGS argv);
bool _emval_has_function(
EM_VAL value,
const char* methodName);
}
template<const char* address>
- struct symbol_registrar {
+ struct symbol_registrar {
symbol_registrar() {
internal::_emval_register_symbol(address);
}
@@ -66,19 +73,21 @@ namespace emscripten {
template<typename ReturnType, typename... Args>
struct Signature {
+ /*
typedef typename BindingType<ReturnType>::WireType (*MethodCaller)(
EM_VAL value,
const char* methodName,
EM_DESTRUCTORS* destructors,
typename BindingType<Args>::WireType...);
+ */
- static MethodCaller get_method_caller() {
- static MethodCaller fp = reinterpret_cast<MethodCaller>(init_method_caller());
- return fp;
+ static EM_METHOD_CALLER get_method_caller() {
+ static EM_METHOD_CALLER mc = init_method_caller();
+ return mc;
}
private:
- static GenericFunction init_method_caller() {
+ static EM_METHOD_CALLER init_method_caller() {
WithPolicies<>::ArgTypeList<ReturnType, Args...> args;
return _emval_get_method_caller(args.count, args.types);
}
@@ -100,19 +109,119 @@ namespace emscripten {
EM_DESTRUCTORS destructors;
};
+ template<typename WireType>
+ struct GenericWireTypeConverter {
+ static WireType from(double wt) {
+ return static_cast<WireType>(wt);
+ }
+ };
+
+ template<typename Pointee>
+ struct GenericWireTypeConverter<Pointee*> {
+ static Pointee* from(double wt) {
+ return reinterpret_cast<Pointee*>(static_cast<uintptr_t>(wt));
+ }
+ };
+
+ template<typename T>
+ T fromGenericWireType(double g) {
+ typedef typename BindingType<T>::WireType WireType;
+ WireType wt = GenericWireTypeConverter<WireType>::from(g);
+ return BindingType<T>::fromWireType(wt);
+ }
+
+ template<typename... Args>
+ struct PackSize;
+
+ template<>
+ struct PackSize<> {
+ static constexpr size_t value = 0;
+ };
+
+ template<typename Arg, typename... Args>
+ struct PackSize<Arg, Args...> {
+ static constexpr size_t value = (sizeof(typename BindingType<Arg>::WireType) + 7) / 8 + PackSize<Args...>::value;
+ };
+
+ union GenericWireType {
+ union {
+ unsigned u;
+ float f;
+ const void* p;
+ } w[2];
+ double d;
+ };
+ static_assert(sizeof(GenericWireType) == 8, "GenericWireType must be 8 bytes");
+ static_assert(alignof(GenericWireType) == 8, "GenericWireType must be 8-byte-aligned");
+
+ inline void writeGenericWireType(GenericWireType*& cursor, float wt) {
+ cursor->w[0].f = wt;
+ ++cursor;
+ }
+
+ inline void writeGenericWireType(GenericWireType*& cursor, double wt) {
+ cursor->d = wt;
+ ++cursor;
+ }
+
+ template<typename T>
+ void writeGenericWireType(GenericWireType*& cursor, T* wt) {
+ cursor->w[0].p = wt;
+ ++cursor;
+ }
+
+ inline void writeGenericWireType(GenericWireType*& cursor, const memory_view& wt) {
+ cursor[0].w[0].u = static_cast<unsigned>(wt.type);
+ cursor[0].w[1].u = wt.size;
+ cursor[1].w[0].p = wt.data;
+ cursor += 2;
+ }
+
+ template<typename T>
+ void writeGenericWireType(GenericWireType*& cursor, T wt) {
+ cursor->w[0].u = static_cast<unsigned>(wt);
+ ++cursor;
+ }
+
+ inline void writeGenericWireTypes(GenericWireType*&) {
+ }
+
+ template<typename First, typename... Rest>
+ EMSCRIPTEN_ALWAYS_INLINE void writeGenericWireTypes(GenericWireType*& cursor, First&& first, Rest&&... rest) {
+ writeGenericWireType(cursor, BindingType<First>::toWireType(std::forward<First>(first)));
+ writeGenericWireTypes(cursor, std::forward<Rest>(rest)...);
+ }
+
+ template<typename... Args>
+ struct WireTypePack {
+ WireTypePack(Args&&... args) {
+ GenericWireType* cursor = elements.data();
+ writeGenericWireTypes(cursor, std::forward<Args>(args)...);
+ }
+
+ operator EM_VAR_ARGS() const {
+ return elements.data();
+ }
+
+ private:
+ std::array<GenericWireType, PackSize<Args...>::value> elements;
+ };
+
template<typename ReturnType, typename... Args>
struct MethodCaller {
static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) {
auto caller = Signature<ReturnType, Args...>::get_method_caller();
+ WireTypePack<Args...> argv(std::forward<Args>(args)...);
EM_DESTRUCTORS destructors;
- auto wireType = caller(
+ EM_GENERIC_WIRE_TYPE result = _emval_call_method(
+ caller,
handle,
methodName,
&destructors,
- toWireType(std::forward<Args>(args))...);
+ argv);
DestructorsRunner rd(destructors);
- return BindingType<ReturnType>::fromWireType(wireType);
+ return fromGenericWireType<ReturnType>(result);
}
};
@@ -121,12 +230,14 @@ namespace emscripten {
static void call(EM_VAL handle, const char* methodName, Args&&... args) {
auto caller = Signature<void, Args...>::get_method_caller();
+ WireTypePack<Args...> argv(std::forward<Args>(args)...);
EM_DESTRUCTORS destructors;
- caller(
+ _emval_call_method(
+ caller,
handle,
methodName,
&destructors,
- toWireType(std::forward<Args>(args))...);
+ argv);
DestructorsRunner rd(destructors);
// void requires no translation
}
@@ -185,9 +296,13 @@ namespace emscripten {
template<typename T>
explicit val(T&& value) {
+ using namespace internal;
+
typedef internal::BindingType<T> BT;
- auto taker = reinterpret_cast<internal::EM_VAL (*)(internal::TYPEID, typename BT::WireType)>(&internal::_emval_take_value);
- handle = taker(internal::TypeID<T>::get(), BT::toWireType(std::forward<T>(value)));
+ WireTypePack<T> argv(std::forward<T>(value));
+ handle = _emval_take_value(
+ internal::TypeID<T>::get(),
+ argv);
}
val() = delete;
@@ -235,20 +350,15 @@ namespace emscripten {
using namespace internal;
WithPolicies<>::ArgTypeList<Args...> argList;
+ WireTypePack<Args...> argv(std::forward<Args>(args)...);
// todo: this is awfully similar to operator(), can we
// merge them somehow?
- typedef EM_VAL (*TypedNew)(
- EM_VAL,
- unsigned,
- TYPEID argTypes[],
- typename BindingType<Args>::WireType...);
- TypedNew typedNew = reinterpret_cast<TypedNew>(&_emval_new);
return val(
- typedNew(
+ _emval_new(
handle,
argList.count,
argList.types,
- toWireType(std::forward<Args>(args))...));
+ argv));
}
template<typename T>
@@ -266,18 +376,13 @@ namespace emscripten {
using namespace internal;
WithPolicies<>::ArgTypeList<Args...> argList;
- typedef EM_VAL (*TypedCall)(
- EM_VAL,
- unsigned,
- TYPEID argTypes[],
- typename BindingType<Args>::WireType...);
- TypedCall typedCall = reinterpret_cast<TypedCall>(&_emval_call);
+ WireTypePack<Args...> argv(std::forward<Args>(args)...);
return val(
- typedCall(
+ _emval_call(
handle,
argList.count,
argList.types,
- toWireType(std::forward<Args>(args))...));
+ argv));
}
template<typename ReturnValue, typename... Args>
@@ -297,16 +402,13 @@ namespace emscripten {
typedef BindingType<T> BT;
- typedef typename BT::WireType (*TypedAs)(
- EM_VAL value,
- TYPEID returnType,
- EM_DESTRUCTORS* runDestructors);
- TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as);
-
EM_DESTRUCTORS destructors;
- typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &destructors);
+ EM_GENERIC_WIRE_TYPE result = _emval_as(
+ handle,
+ TypeID<T>::get(),
+ &destructors);
DestructorsRunner dr(destructors);
- return BT::fromWireType(wt);
+ return fromGenericWireType<T>(result);
}
private:
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index c3ce8dd0..05b3ac33 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -12,6 +12,8 @@
#include <memory>
#include <string>
+#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline))
+
namespace emscripten {
namespace internal {
typedef void (*GenericFunction)();
diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp
index 12264dfd..f43d1ea1 100644
--- a/system/lib/embind/bind.cpp
+++ b/system/lib/embind/bind.cpp
@@ -8,6 +8,7 @@
#include <algorithm>
#include <emscripten/emscripten.h>
#include <climits>
+#include <limits>
using namespace emscripten;
@@ -36,25 +37,39 @@ extern "C" {
}
}
+namespace {
+ template<typename T>
+ static void register_integer(const char* name) {
+ using namespace internal;
+ _embind_register_integer(TypeID<T>::get(), name, sizeof(T), std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
+ }
+
+ template<typename T>
+ static void register_float(const char* name) {
+ using namespace internal;
+ _embind_register_float(TypeID<T>::get(), name, sizeof(T));
+ }
+}
+
EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
using namespace emscripten::internal;
_embind_register_void(TypeID<void>::get(), "void");
- _embind_register_bool(TypeID<bool>::get(), "bool", true, false);
-
- _embind_register_integer(TypeID<char>::get(), "char", CHAR_MIN, CHAR_MAX);
- _embind_register_integer(TypeID<signed char>::get(), "signed char", SCHAR_MIN, SCHAR_MAX);
- _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char", 0, UCHAR_MAX);
- _embind_register_integer(TypeID<signed short>::get(), "short", SHRT_MIN, SHRT_MAX);
- _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short", 0, USHRT_MAX);
- _embind_register_integer(TypeID<signed int>::get(), "int", INT_MIN, INT_MAX);
- _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int", 0, UINT_MAX);
- _embind_register_integer(TypeID<signed long>::get(), "long", LONG_MIN, LONG_MAX);
- _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long", 0, ULONG_MAX);
+ _embind_register_bool(TypeID<bool>::get(), "bool", sizeof(bool), true, false);
+
+ register_integer<char>("char");
+ register_integer<signed char>("signed char");
+ register_integer<unsigned char>("unsigned char");
+ register_integer<signed short>("short");
+ register_integer<unsigned short>("unsigned short");
+ register_integer<signed int>("int");
+ register_integer<unsigned int>("unsigned int");
+ register_integer<signed long>("long");
+ register_integer<unsigned long>("unsigned long");
- _embind_register_float(TypeID<float>::get(), "float");
- _embind_register_float(TypeID<double>::get(), "double");
+ register_float<float>("float");
+ register_float<double>("double");
_embind_register_std_string(TypeID<std::string>::get(), "std::string");
_embind_register_std_wstring(TypeID<std::wstring>::get(), sizeof(wchar_t), "std::wstring");
diff --git a/tests/cases/fixablebadcasts_fastcomp.ll b/tests/cases/fixablebadcasts_fastcomp.ll
new file mode 100644
index 00000000..3870e0e0
--- /dev/null
+++ b/tests/cases/fixablebadcasts_fastcomp.ll
@@ -0,0 +1,27 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128"
+target triple = "asmjs-unknown-emscripten"
+
+@.str = private unnamed_addr constant [18 x i8] c"hello, world %d!\0A\00", align 1
+
+; [#uses=0]
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ store i32 0, i32* %retval
+ %a = call i32 bitcast (i32 (i32)* @twoparam to i32 (i32, i32)*)(i32 5, i32 6)
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %a) ; [#uses=0 type=i32]
+ call void bitcast (void (i32, i32*, i32*)* @_ZN7WebCore33signedPublicKeyAndChallengeStringEjRKN3WTF6StringERKNS_3URLE to void (i32*, i32, i32*, i32*)*)(i32* sret null, i32 0, i32* null, i32* null)
+ ret i32 1
+}
+
+define i32 @twoparam(i32 %x) {
+ ret i32 %x
+}
+
+define void @_ZN7WebCore33signedPublicKeyAndChallengeStringEjRKN3WTF6StringERKNS_3URLE(i32, i32* nocapture, i32* nocapture) {
+ ret void
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
diff --git a/tests/cases/fixablebadcasts_fastcomp.txt b/tests/cases/fixablebadcasts_fastcomp.txt
new file mode 100644
index 00000000..47abd748
--- /dev/null
+++ b/tests/cases/fixablebadcasts_fastcomp.txt
@@ -0,0 +1 @@
+hello, world 5!
diff --git a/tests/cases/returnnan_fastcomp.ll b/tests/cases/returnnan_fastcomp.ll
new file mode 100644
index 00000000..3a6a9f9e
--- /dev/null
+++ b/tests/cases/returnnan_fastcomp.ll
@@ -0,0 +1,34 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128"
+target triple = "asmjs-unknown-emscripten"
+
+@.str = private unnamed_addr constant [18 x i8] c"hello, world %f!\0A\00", align 1
+
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4
+ store i32 0, i32* %retval
+ %f = call double @nand()
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), double %f)
+ %g = call double @zerod()
+ %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), double %g)
+ %h = call float @zerof()
+ %hd = fpext float %h to double
+ %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), double %hd)
+ ret i32 1
+}
+
+define double @nand() unnamed_addr align 2 {
+ ret double 0x7FF8000000000000
+}
+
+define double @zerod() unnamed_addr align 2 {
+ ret double 0x0000000000000000
+}
+
+define float @zerof() unnamed_addr align 2 {
+ ret float 0x0000000000000000
+}
+
+declare i32 @printf(i8*, ...)
+
diff --git a/tests/cases/returnnan_fastcomp.txt b/tests/cases/returnnan_fastcomp.txt
new file mode 100644
index 00000000..f11733ba
--- /dev/null
+++ b/tests/cases/returnnan_fastcomp.txt
@@ -0,0 +1,3 @@
+hello, world nan!
+hello, world 0.000000!
+hello, world 0.000000!
diff --git a/tests/core/test_inlinejs3.in b/tests/core/test_inlinejs3.in
index b45abe95..c3b9b769 100644
--- a/tests/core/test_inlinejs3.in
+++ b/tests/core/test_inlinejs3.in
@@ -13,6 +13,7 @@ int main(int argc, char **argv) {
EM_ASM(Module.print('hello dere3'); Module.print('hello dere' + 4););
}
EM_ASM_({ Module.print('hello input ' + $0) }, 123);
+ EM_ASM_ARGS({ Module.print('hello input ' + $0) }, 456);
int sum = 0;
for (int i = 0; i < argc * 3; i++) {
sum += EM_ASM_INT({
diff --git a/tests/core/test_inlinejs3.out b/tests/core/test_inlinejs3.out
index 5d185adc..c48cc3c8 100644
--- a/tests/core/test_inlinejs3.out
+++ b/tests/core/test_inlinejs3.out
@@ -7,6 +7,7 @@ hello dere4
hello dere3
hello dere4
hello input 123
+hello input 456
i: 0,0.00
i: 1,0.08
i: 2,0.17
diff --git a/tests/dirent/test_readdir_empty.c b/tests/dirent/test_readdir_empty.c
new file mode 100644
index 00000000..00102733
--- /dev/null
+++ b/tests/dirent/test_readdir_empty.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+
+int main(int argc, char** argv) {
+ if (mkdir("/tmp", S_IRWXG) != 0 && errno != EEXIST) {
+ printf("Unable to create dir '/tmp'\n");
+ return -1;
+ }
+
+ if (mkdir("/tmp/1", S_IRWXG) != 0 && errno != EEXIST) {
+ printf("Unable to create dir '/tmp/1'\n");
+ return -1;
+ }
+
+ if (mkdir("/tmp/1/", S_IRWXG) != 0 && errno != EEXIST) {
+ printf("Unable to create dir '/tmp/1/'\n");
+ return -1;
+ }
+
+ DIR *dir = opendir("/tmp");
+
+ if (!dir) {
+ printf("Unable to open dir '/tmp'\n");
+ return -2;
+ }
+
+ struct dirent *dirent;
+
+ while ((dirent = readdir(dir)) != 0) {
+ printf("Found '%s'\n", dirent->d_name);
+
+ if (strlen(dirent->d_name) == 0) {
+ printf("Found empty path!\n");
+ return -3;
+ }
+ }
+
+ closedir(dir);
+
+ printf("success\n");
+ return 0;
+}
+
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index 5ca972be..e2160c33 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1938,10 +1938,84 @@ module({
derived.delete();
// Let the memory leak test superfixture check that no leaks occurred.
});
+
+ BaseFixture.extend("val::as", function() {
+ test("built-ins", function() {
+ assert.equal(true, cm.val_as_bool(true));
+ assert.equal(false, cm.val_as_bool(false));
+ assert.equal(127, cm.val_as_char(127));
+ assert.equal(32767, cm.val_as_short(32767));
+ assert.equal(65536, cm.val_as_int(65536));
+ assert.equal(65536, cm.val_as_long(65536));
+ assert.equal(10.5, cm.val_as_float(10.5));
+ assert.equal(10.5, cm.val_as_double(10.5));
+
+ assert.equal("foo", cm.val_as_string("foo"));
+ assert.equal("foo", cm.val_as_wstring("foo"));
+
+ var obj = {};
+ assert.equal(obj, cm.val_as_val(obj));
+
+ // JS->C++ memory view not implemented
+ //var ab = cm.val_as_memory_view(new ArrayBuffer(13));
+ //assert.equal(13, ab.byteLength);
+ });
+
+ test("value types", function() {
+ var tuple = [1, 2, 3, 4];
+ assert.deepEqual(tuple, cm.val_as_value_array(tuple));
+
+ var struct = {x: 1, y: 2, z: 3, w: 4};
+ assert.deepEqual(struct, cm.val_as_value_object(struct));
+ });
+
+ test("enums", function() {
+ assert.equal(cm.Enum.ONE, cm.val_as_enum(cm.Enum.ONE));
+ });
+ });
+
+ BaseFixture.extend("val::new_", function() {
+ test("variety of types", function() {
+ function factory() {
+ this.arguments = Array.prototype.slice.call(arguments, 0);
+ }
+ var instance = cm.construct_with_6_arguments(factory);
+ assert.deepEqual(
+ [6, -12.5, "a3", {x: 1, y: 2, z: 3, w: 4}, cm.EnumClass.TWO, [-1, -2, -3, -4]],
+ instance.arguments);
+ });
+
+ test("memory view", function() {
+ function factory(before, view, after) {
+ this.before = before;
+ this.view = view;
+ this.after = after;
+ }
+
+ var instance = cm.construct_with_memory_view(factory);
+ assert.equal("before", instance.before);
+ assert.equal(10, instance.view.byteLength);
+ assert.equal("after", instance.after);
+ });
+
+ test("ints_and_float", function() {
+ function factory(a, b, c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+
+ var instance = cm.construct_with_ints_and_float(factory);
+ assert.equal(65537, instance.a);
+ assert.equal(4.0, instance.b);
+ assert.equal(65538, instance.c);
+ });
+ });
});
/* global run_all_tests */
// If running as part of the emscripten test runner suite, and not as part of the IMVU suite,
// we launch the test execution from here. IMVU suite uses its own dedicated mechanism instead of this.
-if (typeof run_all_tests !== "undefined")
+if (typeof run_all_tests !== "undefined") {
run_all_tests();
+}
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index 4efc4bd8..d299660a 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -842,7 +842,7 @@ Enum emval_test_take_and_return_Enum(Enum e) {
return e;
}
-enum class EnumClass { ONE, TWO };
+enum class EnumClass : char { ONE, TWO };
EnumClass emval_test_take_and_return_EnumClass(EnumClass e) {
return e;
@@ -2304,3 +2304,60 @@ EMSCRIPTEN_BINDINGS(mixins) {
.constructor<>()
);
}
+
+template<typename T>
+T val_as(const val& v) {
+ return v.as<T>();
+}
+
+EMSCRIPTEN_BINDINGS(val_as) {
+ function("val_as_bool", &val_as<bool>);
+ function("val_as_char", &val_as<char>);
+ function("val_as_short", &val_as<short>);
+ function("val_as_int", &val_as<int>);
+ function("val_as_long", &val_as<long>);
+
+ function("val_as_float", &val_as<float>);
+ function("val_as_double", &val_as<double>);
+
+ function("val_as_string", &val_as<std::string>);
+ function("val_as_wstring", &val_as<std::wstring>);
+ function("val_as_val", &val_as<val>);
+
+ function("val_as_value_object", &val_as<StructVector>);
+ function("val_as_value_array", &val_as<TupleVector>);
+
+ function("val_as_enum", &val_as<Enum>);
+
+ // memory_view is always JS -> C++
+ //function("val_as_memory_view", &val_as<memory_view>);
+}
+
+val construct_with_6(val factory) {
+ unsigned char a1 = 6;
+ double a2 = -12.5;
+ std::string a3("a3");
+ StructVector a4(1, 2, 3, 4);
+ EnumClass a5 = EnumClass::TWO;
+ TupleVector a6(-1, -2, -3, -4);
+ return factory.new_(a1, a2, a3, a4, a5, a6);
+}
+
+val construct_with_memory_view(val factory) {
+ static const char data[11] = "0123456789";
+ return factory.new_(
+ std::string("before"),
+ memory_view(10, data),
+ std::string("after"));
+}
+
+val construct_with_ints_and_float(val factory) {
+ static const char data[11] = "0123456789";
+ return factory.new_(65537, 4.0f, 65538);
+}
+
+EMSCRIPTEN_BINDINGS(val_new_) {
+ function("construct_with_6_arguments", &construct_with_6);
+ function("construct_with_memory_view", &construct_with_memory_view);
+ function("construct_with_ints_and_float", &construct_with_ints_and_float);
+}
diff --git a/tests/fs/test_idbfs_sync.c b/tests/fs/test_idbfs_sync.c
index ff356416..0d8f4d71 100644
--- a/tests/fs/test_idbfs_sync.c
+++ b/tests/fs/test_idbfs_sync.c
@@ -1,8 +1,6 @@
#include <stdio.h>
#include <emscripten.h>
-#define EM_ASM_REEXPAND(x) EM_ASM(x)
-
void success() {
int result = 1;
REPORT_RESULT();
@@ -15,31 +13,35 @@ int main() {
);
#if FIRST
- // store local files to backing IDB
- EM_ASM_REEXPAND(
+ // store local files to backing IDB. Note that we use the JS FS API for everything here, but we
+ // could use normal libc fwrite etc. to do the writing. All we need the JS FS API for is to
+ // mount the filesystem and do syncfs.
+ EM_ASM_ARGS({
FS.writeFile('/working/waka.txt', 'az');
- FS.writeFile('/working/moar.txt', SECRET);
+ FS.writeFile('/working/moar.txt', $0);
FS.syncfs(function (err) {
assert(!err);
- ccall('success', 'v', '', []);
+ ccall('success', 'v');
});
- );
+ }, SECRET);
#else
// load files from backing IDB
- EM_ASM_REEXPAND(
+ EM_ASM_ARGS({
FS.syncfs(true, function (err) {
assert(!err);
var contents = FS.readFile('/working/waka.txt', { encoding: 'utf8' });
- assert(contents === 'az');
+ assert(contents === 'az', 'bad contents ' + contents);
- var secret = FS.readFile('/working/moar.txt', { encoding: 'utf8' });
- assert(secret === SECRET);
+ // note we convert to a number here (using +), since we used writeFile, which writes a
+ // JS string.
+ var secret = +FS.readFile('/working/moar.txt', { encoding: 'utf8' });
+ assert(secret === $0, 'bad secret ' + [secret, $0, typeof secret, typeof $0]);
ccall('success', 'v', '', []);
});
- );
+ }, SECRET);
#endif
emscripten_exit_with_live_runtime();
diff --git a/tests/hello_world.ll b/tests/hello_world.ll
index ab4b199f..7090b732 100644
--- a/tests/hello_world.ll
+++ b/tests/hello_world.ll
@@ -2,16 +2,15 @@
target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128"
target triple = "asmjs-unknown-emscripten"
-@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*]
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1
-; [#uses=0]
define i32 @main() {
entry:
- %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ %retval = alloca i32, align 4
store i32 0, i32* %retval
- %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32]
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0))
ret i32 1
}
-; [#uses=1]
declare i32 @printf(i8*, ...)
+
diff --git a/tests/test_core.py b/tests/test_core.py
index 885a0c52..d5b855b9 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -4097,6 +4097,10 @@ def process(filename):
src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read()
self.do_run(src, 'success', force_c=True)
+ def test_readdir_empty(self):
+ src = open(path_from_root('tests', 'dirent', 'test_readdir_empty.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
def test_stat(self):
src = open(path_from_root('tests', 'stat', 'test_stat.c'), 'r').read()
self.do_run(src, 'success', force_c=True)
diff --git a/tests/test_other.py b/tests/test_other.py
index 0f5a4191..aae399c8 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -2536,9 +2536,10 @@ int main()
(['-Wno-error=implicit-function-declaration'], ['abort()', 'it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this'], [IMPLICIT_WARNING]), # turn error into warning
(['-Wno-implicit-function-declaration'], ['abort()', 'it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this'], []), # turn error into nothing at all
(['-Wno-error=implicit-function-declaration', '-s', 'ASSERTIONS=2'], ['abort()', 'This pointer might make sense in another type signature'], []),
- (['-Wno-error=implicit-function-declaration', '-O1'], ['hello 2\nhello 5\n'], []), # invalid output - second arg is sent as varargs, but needs to be int. llvm optimizer avoided the crash silently, caused undefined behavior... at least people can debug this by running an -O0 build.
+ (['-Wno-error=implicit-function-declaration', '-O1'], ['hello 0\nhello 0\n'], []), # invalid output - second arg is sent as varargs, but needs to be int. llvm optimizer avoided the crash silently, caused undefined behavior... at least people can debug this by running an -O0 build.
]:
print opts, expected
+ try_delete('a.out.js')
stdout, stderr = Popen([PYTHON, EMCC, 'src.c'] + opts, stderr=PIPE).communicate()
for ce in compile_expected + ['''warning: incompatible pointer types''']:
self.assertContained(ce, stderr)
@@ -2580,6 +2581,19 @@ int main()
out, err = Popen([PYTHON, EMCC, 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
assert 'warning' in err, err
assert 'incorrect target triple' in err, err
+
+ def test_valid_abspath(self):
+ # Test whether abspath warning appears
+ abs_include_path = path_from_root('tests')
+ process = Popen([PYTHON, EMCC, '-I%s' % abs_include_path, path_from_root('tests', 'hello_world.c')], stdout=PIPE, stderr=PIPE)
+ out, err = process.communicate()
+ warning = '-I or -L of an absolute path "-I%s" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript). Pass \'-Wno-warn-absolute-paths\' to emcc to hide this warning.' % abs_include_path
+ assert(warning in err)
+
+ # Hide warning for this include path
+ process = Popen([PYTHON, EMCC, '--valid-abspath', abs_include_path,'-I%s' % abs_include_path, path_from_root('tests', 'hello_world.c')], stdout=PIPE, stderr=PIPE)
+ out, err = process.communicate()
+ assert(warning not in err)
def test_simplify_ifs(self):
def test(src, nums):
diff --git a/tools/shared.py b/tools/shared.py
index ac4b42ea..5425d2c1 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -678,18 +678,31 @@ USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK')
if USE_EMSDK:
# Disable system C and C++ include directories, and add our own (using -idirafter so they are last, like system dirs, which
# allows projects to override them)
- EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc',
- '-Xclang', '-isystem' + path_from_root('system', 'local', 'include'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'compat'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'),
- '-Xclang', '-isystem' + path_from_root('system', 'include'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'bsd'), # posix stuff
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'libc'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'gfx'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'net'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'SDL'),
+ C_INCLUDE_PATHS = [path_from_root('system', 'local', 'include'),
+ path_from_root('system', 'include', 'compat'),
+ path_from_root('system', 'include'),
+ path_from_root('system', 'include', 'emscripten'),
+ path_from_root('system', 'include', 'bsd'), # posix stuff
+ path_from_root('system', 'include', 'libc'),
+ path_from_root('system', 'include', 'gfx'),
+ path_from_root('system', 'include', 'net'),
+ path_from_root('system', 'include', 'SDL'),
]
+
+ CXX_INCLUDE_PATHS = [path_from_root('system', 'include', 'libcxx')
+ ]
+
+ C_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc',
+ ]
+
+ def include_directive(paths):
+ result = []
+ for path in paths:
+ result += ['-Xclang', '-isystem' + path]
+ return result
+
+ EMSDK_OPTS = C_OPTS + include_directive(C_INCLUDE_PATHS) + include_directive(CXX_INCLUDE_PATHS)
+
EMSDK_OPTS += COMPILER_STANDARDIZATION_OPTS
# For temporary compatibility, treat 'le32-unknown-nacl' as 'asmjs-unknown-emscripten'.
if LLVM_TARGET != 'asmjs-unknown-emscripten' and \
@@ -709,14 +722,13 @@ else:
# Engine tweaks
try:
- SPIDERMONKEY_ENGINE = listify(SPIDERMONKEY_ENGINE)
- if 'gcparam' not in str(SPIDERMONKEY_ENGINE):
- new_spidermonkey = SPIDERMONKEY_ENGINE
+ new_spidermonkey = listify(SPIDERMONKEY_ENGINE)
+ if 'gcparam' not in str(new_spidermonkey):
new_spidermonkey += ['-e', "gcparam('maxBytes', 1024*1024*1024);"] # Our very large files need lots of gc heap
- JS_ENGINES = map(lambda x: x if x != SPIDERMONKEY_ENGINE else new_spidermonkey, JS_ENGINES)
- SPIDERMONKEY_ENGINE = new_spidermonkey
- if '-w' not in SPIDERMONKEY_ENGINE:
- SPIDERMONKEY_ENGINE += ['-w']
+ if '-w' not in str(new_spidermonkey):
+ new_spidermonkey += ['-w']
+ JS_ENGINES = map(lambda x: new_spidermonkey if x == SPIDERMONKEY_ENGINE else x, JS_ENGINES)
+ SPIDERMONKEY_ENGINE = new_spidermonkey
except NameError:
pass