aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormax99x <max99x@gmail.com>2011-09-13 02:14:32 +0300
committermax99x <max99x@gmail.com>2011-09-13 02:14:32 +0300
commitc5e5c90cd111c08b3d91d1bc89ba7d33a308cbc7 (patch)
tree5c6033729c4a4c5593fcd87bd9ffa6debf21f285
parent91e29b31f280b879b10debf2194c2b87d94857cf (diff)
parent534cc7f05846daa88f2d3f2d149d9768262033e9 (diff)
Merge remote-tracking branch 'upstream/master'
Conflicts: src/intertyper.js tests/runner.py
-rw-r--r--settings.py2
-rw-r--r--src/analyzer.js36
-rw-r--r--src/compiler.js3
-rw-r--r--src/intertyper.js9
-rw-r--r--src/jsifier.js9
-rw-r--r--src/library.js12
-rw-r--r--src/parseTools.js16
-rw-r--r--src/preamble.js12
-rw-r--r--src/settings.js10
-rw-r--r--tests/runner.py123
-rwxr-xr-xtools/bindings_generator.py126
-rwxr-xr-xtools/emmaken.py23
-rw-r--r--tools/shared.py3
13 files changed, 294 insertions, 90 deletions
diff --git a/settings.py b/settings.py
index cf4fd28c..c6d63341 100644
--- a/settings.py
+++ b/settings.py
@@ -13,7 +13,7 @@ COMPILER_OPTS = ['-m32'] # Need to build as 32bit arch, for now -
# various errors on 64bit compilation
# WARNING: '-g' here will generate llvm bitcode that lli will crash on!
-SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/mozilla-central/js/src/js'), '-m', '-j', '-p']
+SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/mozilla-central/js/src/js'), '-m', '-n']
V8_ENGINE = [os.path.expanduser('~/Dev/v8/d8')]
#COMPILER_ENGINE=SPIDERMONKEY_ENGINE # XXX Warning: currently appears to be broken on trunk, some file reading issue
diff --git a/src/analyzer.js b/src/analyzer.js
index 96e6297b..824e7903 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -275,25 +275,27 @@ function analyzer(data) {
}
});
- // Second pass over variables - notice when types are crossed by bitcast
-
- func.lines.forEach(function(item) {
- if (item.intertype === 'assign' && item.value.intertype === 'bitcast') {
- // bitcasts are unique in that they convert one pointer to another. We
- // sometimes need to know the original type of a pointer, so we save that.
- //
- // originalType is the type this variable is created from
- // derivedTypes are the types that this variable is cast into
- func.variables[item.ident].originalType = item.value.type2;
-
- if (!isNumber(item.value.ident)) {
- if (!func.variables[item.value.ident].derivedTypes) {
- func.variables[item.value.ident].derivedTypes = [];
+ if (QUANTUM_SIZE === 1) {
+ // Second pass over variables - notice when types are crossed by bitcast
+
+ func.lines.forEach(function(item) {
+ if (item.intertype === 'assign' && item.value.intertype === 'bitcast') {
+ // bitcasts are unique in that they convert one pointer to another. We
+ // sometimes need to know the original type of a pointer, so we save that.
+ //
+ // originalType is the type this variable is created from
+ // derivedTypes are the types that this variable is cast into
+ func.variables[item.ident].originalType = item.value.type2;
+
+ if (!isNumber(item.value.ident)) {
+ if (!func.variables[item.value.ident].derivedTypes) {
+ func.variables[item.value.ident].derivedTypes = [];
+ }
+ func.variables[item.value.ident].derivedTypes.push(item.value.type);
}
- func.variables[item.value.ident].derivedTypes.push(item.value.type);
}
- }
- });
+ });
+ }
for (vname in func.variables) {
var variable = func.variables[vname];
diff --git a/src/compiler.js b/src/compiler.js
index 8980da93..9bf81ba4 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -71,6 +71,9 @@ eval(processMacros(preprocess(read('runtime.js'))));
// Read llvm
var raw = read(ll_file);
+if (FAKE_X86_FP80) {
+ raw = raw.replace(/x86_fp80/g, 'double');
+}
var lines = raw.split('\n');
raw = null;
diff --git a/src/intertyper.js b/src/intertyper.js
index 7649203a..7d74dfd2 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -543,7 +543,9 @@ function intertyper(data, parseFunctions, baseLineNum) {
item.intertype = 'bitcast';
item.type = item.tokens[4].text; // The final type
Types.needAnalysis[item.type] = 0;
- item.ident = toNiceIdent(item.tokens[2].text);
+ var to = getTokenIndexByText(item.tokens, 'to');
+ item.params = [parseLLVMSegment(item.tokens.slice(2, to))];
+ item.ident = item.params[0].ident;
item.type2 = item.tokens[1].text; // The original type
Types.needAnalysis[item.type2] = 0;
this.forwardItem(item, 'Reintegrator');
@@ -791,13 +793,10 @@ function intertyper(data, parseFunctions, baseLineNum) {
// external function stub
substrate.addActor('External', {
processItem: function(item) {
- if (item.tokens[1].text in LLVM.LINKAGES || item.tokens[1].text in LLVM.PARAM_ATTR) {
+ if (item.tokens[1].text in LLVM.LINKAGES || item.tokens[1].text in LLVM.PARAM_ATTR || item.tokens[1].text in LLVM.VISIBILITIES) {
item.tokens.splice(1, 1);
}
- if (item.tokens[1].text == 'hidden') {
- item.tokens = [item.tokens[0]].concat(item.tokens.slice(2));
- }
var params = parseParamTokens(item.tokens[3].item.tokens);
return [{
intertype: 'functionStub',
diff --git a/src/jsifier.js b/src/jsifier.js
index 1124b008..1fd4a790 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -253,6 +253,10 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
constant = makePointer(constant, null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', item.type);
var js = item.ident + '=' + constant + ';';
+ // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
+ if (item.ident.substr(0, 5) == '__ZTV') {
+ js += '\n' + makePointer('[0]', null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', ['void*']) + ';';
+ }
if (item.ident in EXPORTED_GLOBALS) {
js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
}
@@ -603,7 +607,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
makeFuncLineActor('store', function(item) {
var value = finalizeLLVMParameter(item.value);
if (pointingLevels(item.pointerType) == 1) {
- value = parseNumerical(value, removePointing(item.pointerType));
+ value = parseNumerical(value, item.valueType);
}
var impl = VAR_EMULATED;
if (item.pointer.intertype == 'value') {
@@ -776,7 +780,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
makeFuncLineActor('mathop', processMathop);
makeFuncLineActor('bitcast', function(item) {
- return item.ident;
+ return finalizeLLVMParameter(item.params[0]);
});
function makeFunctionCall(ident, params, funcData) {
@@ -876,6 +880,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()), CONSTANTS));
print(pre);
+ print('Runtime.QUANTUM_SIZE = ' + QUANTUM_SIZE);
if (RUNTIME_TYPE_INFO) {
Types.cleanForRuntime();
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
diff --git a/src/library.js b/src/library.js
index 88feb66c..156c1c25 100644
--- a/src/library.js
+++ b/src/library.js
@@ -3758,7 +3758,8 @@ LibraryManager.library = {
strdup: function(ptr) {
var len = String_len(ptr);
var newStr = _malloc(len + 1);
- {{{ makeCopyValues('newStr', 'ptr', 'len + 1', 'null', ' || 0') }}};
+ {{{ makeCopyValues('newStr', 'ptr', 'len', 'null') }}};
+ {{{ makeSetValue('newStr', 'len', '0', 'i8') }}};
return newStr;
},
@@ -4120,6 +4121,14 @@ LibraryManager.library = {
return -1; // 'indeterminable' for FLT_ROUNDS
},
+ llvm_memory_barrier: function(){},
+
+ llvm_atomic_load_add_i32_p0i32: function(ptr, delta) {
+ var ret = {{{ makeGetValue('ptr', '0', 'i32') }}};
+ {{{ makeSetValue('ptr', '0', 'ret+delta', 'i32') }}};
+ return ret;
+ },
+
// ==========================================================================
// iostream.h
// ==========================================================================
@@ -5285,6 +5294,7 @@ LibraryManager.library = {
pthread_mutex_destroy: function() {},
pthread_mutex_lock: function() {},
pthread_mutex_unlock: function() {},
+ pthread_cond_broadcast: function() {},
// ==========================================================================
// malloc.h
diff --git a/src/parseTools.js b/src/parseTools.js
index 88758454..955353b2 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -74,7 +74,7 @@ function toNiceIdent(ident) {
assert(ident);
if (parseFloat(ident) == ident) return ident;
if (ident == 'null') return '0'; // see parseNumerical
- return ident.replace('%', '$').replace(/["&\\ \.@:<>,\*\[\]-]/g, '_');
+ return ident.replace('%', '$').replace(/["&\\ \.@:<>,\*\[\]\(\)-]/g, '_');
}
// Kind of a hack. In some cases we have strings that we do not want
@@ -143,6 +143,7 @@ function isFunctionDef(token) {
}
function isFunctionType(type) {
+ type = type.replace(/"[^"]+"/g, '".."');
var parts = type.split(' ');
if (pointingLevels(type) !== 1) return false;
var text = removeAllPointing(parts.slice(1).join(' '));
@@ -430,6 +431,9 @@ function parseLLVMFunctionCall(segment) {
if (type === '?') {
if (intertype === 'getelementptr') {
type = '*'; // a pointer, we can easily say, this is
+ } else if (intertype === 'bitcast') {
+ assert(segment[2].item.tokens.slice(-2)[0].text === 'to');
+ type = segment[2].item.tokens.slice(-1)[0].text;
}
}
var ret = {
@@ -486,7 +490,15 @@ function IEEEUnHex(stringy) {
stringy = stringy.substr(2); // leading '0x';
if (stringy.replace(/0/g, '') === '') return 0;
while (stringy.length < 16) stringy = '0' + stringy;
- assert(stringy.length === 16, 'Can only unhex 16-digit double numbers, nothing platform-specific');
+ if (FAKE_X86_FP80 && stringy.length > 16) {
+ stringy = stringy.substr(stringy.length-16, 16);
+ if (!Debugging.shownIEEEUnHexWarning) {
+ dprint('WARNING: .ll contains floating-point values with more than 64 bits. Faking values for them.');
+ dprint(' If they are used, this will almost certainly fail!');
+ Debugging.shownIEEEUnHexWarning = true;
+ }
+ }
+ assert(stringy.length === 16, 'Can only unhex 16-digit double numbers, nothing platform-specific'); // |long double| can cause x86_fp80 which causes this
var top = eval('0x' + stringy[0]);
var neg = !!(top & 8); // sign
if (neg) {
diff --git a/src/preamble.js b/src/preamble.js
index 9e0f5ce3..35bb75d7 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -320,7 +320,7 @@ function setValue(ptr, value, type) {
default: abort('invalid type for setValue: ' + type);
}
}
-this['setValue'] = setValue;
+Module['setValue'] = setValue;
// Parallel to setValue.
@@ -338,7 +338,7 @@ function getValue(ptr, type) {
}
return null;
}
-this['getValue'] = getValue;
+Module['getValue'] = getValue;
// Allocates memory for some data and initializes it properly.
@@ -428,7 +428,8 @@ var STACK_ROOT, STACKTOP, STACK_MAX;
var STATICTOP;
var HAS_TYPED_ARRAYS = false;
-var TOTAL_MEMORY = 50*1024*1024;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}};
+var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}};
// Initialize the runtime's memory
#if USE_TYPED_ARRAYS
@@ -459,9 +460,8 @@ if (HAS_TYPED_ARRAYS) {
} else
#endif
{
- // Without this optimization, Chrome is slow. Sadly, the constant here needs to be tweaked depending on the code being run...
- var FAST_MEMORY = TOTAL_MEMORY/32;
- HEAP = new Array(FAST_MEMORY);
+ // Make sure that our HEAP is implemented as a flat array.
+ HEAP = new Array(TOTAL_MEMORY);
for (var i = 0; i < FAST_MEMORY; i++) {
HEAP[i] = 0; // XXX We do *not* use {{| makeSetValue(0, 'i', 0, 'null') |}} here, since this is done just to optimize runtime speed
}
diff --git a/src/settings.js b/src/settings.js
index ed3437b1..ab532e67 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -34,6 +34,12 @@ INVOKE_RUN = 1; // Whether we will call run(). Disable if you embed the generate
// code in your own, and will call run() yourself at the right time
INIT_STACK = 1; // Whether to initialize memory on the stack to 0.
INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to 0.
+FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This ensures it will be
+ // in a flat array. This only matters in non-typed array builds.
+TOTAL_MEMORY = 50*1024*1024; // The total amount of memory to use. This mainly matters in
+ // typed array builds - accessing memory about this value will
+ // return undefined values and lead to serious problems, and there
+ // is currently no warning about that!
// Code embetterments
OPTIMIZE = 0; // Optimize llvm operations into js commands
@@ -129,6 +135,10 @@ RUNTIME_TYPE_INFO = 0; // Whether to expose type info to the script at run time.
// to more easily perform operations from handwritten JS on
// objects with structures etc.
+FAKE_X86_FP80 = 0; // Replaces x86_fp80 with double. This loses precision. It is better,
+ // if you can, to get the original source code to build without x86_fp80
+ // (which is nonportable anyhow).
+
// Compiler debugging options
DEBUG_TAGS_SHOWING = [];
// Some useful items:
diff --git a/tests/runner.py b/tests/runner.py
index c52027a5..ee51238f 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -5,7 +5,7 @@ See settings.py file for options&params. Edit as needed.
'''
from subprocess import Popen, PIPE, STDOUT
-import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, json
+import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, json, difflib
# Setup
@@ -178,7 +178,7 @@ class RunnerCore(unittest.TestCase):
def do_emscripten(self, filename, output_processor=None, append_ext=True, extra_args=[]):
# Run Emscripten
exported_settings = {}
- for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTIONS', 'EXCEPTION_DEBUG']:
+ for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTIONS', 'FAST_MEMORY', 'EXCEPTION_DEBUG']:
try:
value = eval(setting)
exported_settings[setting] = value
@@ -223,17 +223,23 @@ class RunnerCore(unittest.TestCase):
if type(value) is not str: value = value() # lazy loading
if type(string) is not str: string = string()
if value not in string:
- raise Exception("Expected to find '%s' in '%s'" % (limit_size(value), limit_size(string)))
+ raise Exception("Expected to find '%s' in '%s', diff:\n\n%s" % (
+ limit_size(value), limit_size(string),
+ limit_size(''.join([a.rstrip()+'\n' for a in difflib.unified_diff(value.split('\n'), string.split('\n'), fromfile='expected', tofile='actual')]))
+ ))
def assertNotContained(self, value, string):
if type(value) is not str: value = value() # lazy loading
if type(string) is not str: string = string()
if value in string:
- raise Exception("Expected to NOT find '%s' in '%s'" % (limit_size(value), limit_size(string)))
+ raise Exception("Expected to NOT find '%s' in '%s', diff:\n\n%s" % (
+ limit_size(value), limit_size(string),
+ limit_size(''.join([a.rstrip()+'\n' for a in difflib.unified_diff(value.split('\n'), string.split('\n'), fromfile='expected', tofile='actual')]))
+ ))
###################################################################################################
-if 'benchmark' not in sys.argv:
+if 'benchmark' not in str(sys.argv):
# Tests
print "Running Emscripten tests..."
@@ -2987,7 +2993,6 @@ if 'benchmark' not in sys.argv:
self.do_ll_test(path_from_root('tests', 'lua', 'lua.ll'),
'hello lua world!\n17\n1\n2\n3\n4\n7',
- js_engines=[V8_ENGINE], # XXX Moz bug 675269
args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
output_nicerizer=lambda string: string.replace('\n\n', '\n').replace('\n\n', '\n'))
@@ -2997,8 +3002,10 @@ if 'benchmark' not in sys.argv:
# Build a library into a .bc file. We build the .bc file once and cache it for all our tests. (We cache in
# memory since the test directory is destroyed and recreated for each test. Note that we cache separately
# for different compilers)
- def get_library(self, name, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True):
+ def get_library(self, name, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True, build_subdir=None):
if type(generated_libs) is not list: generated_libs = [generated_libs]
+ if build_subdir and configure.startswith('./'):
+ configure = '.' + configure
if GlobalCache is not None:
cache_name = name + '|' + COMPILER
@@ -3014,16 +3021,24 @@ if 'benchmark' not in sys.argv:
project_dir = os.path.join(temp_dir, name)
shutil.copytree(path_from_root('tests', name), project_dir) # Useful in debugging sometimes to comment this out
os.chdir(project_dir)
+ if build_subdir:
+ try:
+ os.mkdir('cbuild')
+ except:
+ pass
+ os.chdir(os.path.join(project_dir, 'cbuild'))
env = os.environ.copy()
env['RANLIB'] = env['AR'] = env['CXX'] = env['CC'] = env['LIBTOOL'] = EMMAKEN
env['EMMAKEN_COMPILER'] = COMPILER
env['EMSCRIPTEN_TOOLS'] = path_from_root('tools')
env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(COMPILER_OPTS + COMPILER_TEST_OPTS) # Normal CFLAGS is ignored by some configure's.
- if configure: # Useful in debugging sometimes to comment this out (and 2 lines below)
+ if configure: # Useful in debugging sometimes to comment this out (and the lines below up to and including the |make| call)
+ env['EMMAKEN_JUST_CONFIGURE'] = '1'
Popen(configure + configure_args, stdout=PIPE, stderr=STDOUT, env=env).communicate()[0]
+ del env['EMMAKEN_JUST_CONFIGURE']
Popen(make + make_args, stdout=PIPE, stderr=STDOUT, env=env).communicate()[0]
bc_file = os.path.join(project_dir, 'bc.bc')
- self.do_link(map(lambda lib: os.path.join(project_dir, lib), generated_libs), bc_file)
+ self.do_link(map(lambda lib: os.path.join(project_dir, 'cbuild', lib) if build_subdir else os.path.join(project_dir, lib), generated_libs), bc_file)
if cache and GlobalCache is not None:
print >> sys.stderr, '<save build into cache> ',
GlobalCache[cache_name] = open(bc_file, 'rb').read()
@@ -3032,7 +3047,7 @@ if 'benchmark' not in sys.argv:
def get_freetype(self):
global INIT_STACK; INIT_STACK = 1 # TODO: Investigate why this is necessary
- return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.so'))
+ return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a.bc'))
def test_freetype(self):
if QUANTUM_SIZE == 1: return self.skip() # TODO: Figure out and try to fix
@@ -3066,10 +3081,25 @@ if 'benchmark' not in sys.argv:
self.do_test(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
- libraries=[self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a'])],
+ libraries=[self.get_library('zlib', os.path.join('libz.a.bc'), make_args=['libz.a'])],
includes=[path_from_root('tests', 'zlib')],
force_c=True)
+ def zzztest_glibc(self):
+ global CORRECT_SIGNS; CORRECT_SIGNS = 1
+ global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
+ global CORRECT_ROUNDINGS; CORRECT_ROUNDINGS = 1
+
+ self.do_test(r'''
+ #include <stdio.h>
+ int main() { printf("hai\n"); return 1; }
+ ''',
+ libraries=[self.get_library('glibc', [os.path.join('src', '.libs', 'libBulletCollision.a.bc'),
+ os.path.join('src', '.libs', 'libBulletDynamics.a.bc'),
+ os.path.join('src', '.libs', 'libLinearMath.a.bc')],
+ configure_args=['--disable-sanity-checks'])],
+ includes=[path_from_root('tests', 'glibc', 'include')])
+
def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
global SAFE_HEAP, SAFE_HEAP_LINES, USE_TYPED_ARRAYS, LLVM_OPTS
@@ -3087,9 +3117,9 @@ if 'benchmark' not in sys.argv:
self.do_test(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(),
- libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a'),
- os.path.join('src', '.libs', 'libBulletDynamics.a'),
- os.path.join('src', '.libs', 'libLinearMath.a')],
+ libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a.bc'),
+ os.path.join('src', '.libs', 'libBulletDynamics.a.bc'),
+ os.path.join('src', '.libs', 'libLinearMath.a.bc')],
configure_args=['--disable-demos','--disable-dependency-tracking'])],
includes=[path_from_root('tests', 'bullet', 'src')],
js_engines=[SPIDERMONKEY_ENGINE]) # V8 issue 1407
@@ -3152,10 +3182,10 @@ if 'benchmark' not in sys.argv:
freetype = self.get_freetype()
poppler = self.get_library('poppler',
- [os.path.join('poppler', '.libs', 'libpoppler.so.13.0.0'),
- os.path.join('goo', '.libs', 'libgoo.a'),
- os.path.join('fofi', '.libs', 'libfofi.a'),
- os.path.join('splash', '.libs', 'libsplash.a'),
+ [os.path.join('poppler', '.libs', 'libpoppler.so.13.0.0.bc'),
+ os.path.join('goo', '.libs', 'libgoo.a.bc'),
+ os.path.join('fofi', '.libs', 'libfofi.a.bc'),
+ os.path.join('splash', '.libs', 'libsplash.a.bc'),
os.path.join('utils', 'pdftoppm.o'),
os.path.join('utils', 'parseargs.o')],
configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms'])
@@ -3168,15 +3198,13 @@ if 'benchmark' not in sys.argv:
self.do_ll_test(combined,
lambda: map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''),
args='-scale-to 512 paper.pdf filename'.split(' '),
- post_build=post,
- js_engines=[V8_ENGINE]) # XXX Moz bug 675269
+ post_build=post)
#, build_ll_hook=self.do_autodebug)
def test_openjpeg(self):
global USE_TYPED_ARRAYS
global CORRECT_SIGNS
if USE_TYPED_ARRAYS == 2:
- return self.skip() # XXX Moz bug 675269
CORRECT_SIGNS = 1
else:
CORRECT_SIGNS = 2
@@ -3201,7 +3229,7 @@ if 'benchmark' not in sys.argv:
open(filename, 'w').write(src)
lib = self.get_library('openjpeg',
- [os.path.join('bin', 'libopenjpeg.so'),
+ [os.path.join('bin', 'libopenjpeg.so.1.4.0.bc'),
os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')),
os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')),
os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')),
@@ -3257,7 +3285,6 @@ if 'benchmark' not in sys.argv:
os.path.join(self.get_building_dir(), 'openjpeg')],
force_c=True,
post_build=post,
- js_engines=[V8_ENGINE], # XXX Moz bug 675269
output_nicerizer=image_compare)# build_ll_hook=self.do_autodebug)
def test_python(self):
@@ -3271,7 +3298,6 @@ if 'benchmark' not in sys.argv:
self.do_ll_test(path_from_root('tests', 'python', 'python.ll'),
'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
- js_engines=[V8_ENGINE], # XXX Moz bug 675269
args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''],
extra_emscripten_args=['-m'])
@@ -3426,6 +3452,10 @@ if 'benchmark' not in sys.argv:
Child2() : Parent(9) { printf("Child2:%d\\n", value); };
int getValCube() { return value*value*value; }
static void printStatic() { printf("*static*\\n"); }
+
+ virtual void virtualFunc() { printf("*virtualf*\\n"); }
+ virtual void virtualFunc2() { printf("*virtualf2*\\n"); }
+ static void runVirtualFunc(Child2 *self) { self->virtualFunc(); };
private:
void doSomethingSecret() { printf("security breached!\\n"); }; // we should not be able to do this
};
@@ -3501,6 +3531,32 @@ if 'benchmark' not in sys.argv:
Child2.prototype.printStatic(); // static calls go through the prototype
+ // virtual function
+ c2.virtualFunc();
+ Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+
+ // extend the class from JS
+ var c3 = new Child2;
+ customizeVTable(c3, [{
+ original: Child2.prototype.virtualFunc,
+ replacement: function() {
+ print('*js virtualf replacement*');
+ }
+ }, {
+ original: Child2.prototype.virtualFunc2,
+ replacement: function() {
+ print('*js virtualf2 replacement*');
+ }
+ }]);
+ c3.virtualFunc();
+ Child2.prototype.runVirtualFunc(c3);
+ c3.virtualFunc2();
+
+ c2.virtualFunc(); // original should remain the same
+ Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+
print('*ok*');
'''
@@ -3539,6 +3595,17 @@ Child2:9
0
1
*static*
+*virtualf*
+*virtualf*
+*virtualf2*
+Parent:9
+Child2:9
+*js virtualf replacement*
+*js virtualf replacement*
+*js virtualf2 replacement*
+*virtualf*
+*virtualf*
+*virtualf2*
*ok*
''', post_build=post2)
@@ -3975,7 +4042,8 @@ TT = %s
self.assertEquals(output, expected)
else:
- # Benchmarks
+ # Benchmarks. Run them with argument |benchmark|. To run a specific test, do
+ # |benchmark.test_X|.
print "Running Emscripten benchmarks..."
@@ -4008,6 +4076,7 @@ else:
CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
LLVM_OPTS = 1
DISABLE_EXCEPTIONS = 1
+ FAST_MEMORY = 10*1024*1024
TEST_REPS = 4
TOTAL_TESTS = 6
@@ -4016,7 +4085,7 @@ else:
total_times = map(lambda x: 0., range(TEST_REPS))
total_native_times = map(lambda x: 0., range(TEST_REPS))
- class Benchmark(RunnerCore):
+ class benchmark(RunnerCore):
def print_stats(self, times, native_times):
mean = sum(times)/len(times)
squared_times = map(lambda x: x*x, times)
@@ -4156,7 +4225,7 @@ else:
old_quantum = QUANTUM_SIZE
old_use_typed_arrays = USE_TYPED_ARRAYS
QUANTUM_SIZE = 1
- USE_TYPED_ARRAYS = 0 # Rounding errors with TA2 are too big in this very rounding-sensitive code
+ USE_TYPED_ARRAYS = 0 # Rounding errors with TA2 are too big in this very rounding-sensitive code. However, TA2 is much faster (2X)
src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read().replace('double', 'float') # benchmark with floats
self.do_benchmark(src, ['7', '256'], '256 256')
diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py
index deba8930..0a1a75cc 100755
--- a/tools/bindings_generator.py
+++ b/tools/bindings_generator.py
@@ -40,6 +40,9 @@ It's only purpose is to make it easy to access the C++ code in the JS
bindings, and to prevent DFE from removing the code we care about. The
JS bindings do more serious work, creating class structures in JS and
linking them to the C bindings.
+
+NOTE: ammo.js is currently the biggest consumer of this code. For some
+ more docs you can see that project's README
'''
import os, sys, glob, re
@@ -105,6 +108,8 @@ for classname, clazz in parsed.classes.iteritems():
struct['name'] = sname # Missing in CppHeaderParser
print 'zz seen struct %s in %s' % (sname, classname)
+print 'zz parents: ', parents
+
for classname, clazz in classes.iteritems():
# Various precalculations
print 'zz precalc', classname
@@ -177,6 +182,9 @@ for classname, clazz in classes.iteritems():
1/0.
# Fill in some missing stuff
+ method['returns_text'] = method['returns_text'].replace('&', '').replace('*', '')
+ if method['returns_text'] in parents:
+ method['returns_text'] = parents[method['returns_text']] + '::' + method['returns_text']
if method.get('returns_const'): method['returns_text'] = 'const ' + method['returns_text']
if method.get('returns_pointer'):
while method['returns_text'].count('*') < method['returns_pointer']:
@@ -355,44 +363,119 @@ gen_js = open(basename + '.js', 'w')
gen_c.write('extern "C" {\n')
-# Use this when calling a binding function when you want to pass a null pointer.
-# Having this object saves us needing to do checks for the object being null each time in the bindings code.
gen_js.write('''
// Bindings utilities
-var Object__cache = {};
-function wrapPointer(ptr, class_) {
- var cache = class_ ? class_.prototype.__cache__ : Object__cache;
+
+var Object__cache = {}; // we do it this way so we do not modify |Object|
+function wrapPointer(ptr, __class__) {
+ var cache = __class__ ? __class__.prototype.__cache__ : Object__cache;
var ret = cache[ptr];
if (ret) return ret;
- class_ = class_ || Object;
- ret = Object.create(class_.prototype);
+ __class__ = __class__ || Object;
+ ret = Object.create(__class__.prototype);
ret.ptr = ptr;
+ ret.__class__ = __class__;
return cache[ptr] = ret;
}
-this['wrapPointer'] = wrapPointer;
+Module['wrapPointer'] = wrapPointer;
-function castObject(obj, class_) {
- return wrapPointer(obj.ptr, class_);
+function castObject(obj, __class__) {
+ return wrapPointer(obj.ptr, __class__);
}
-this['castObject'] = castObject;
+Module['castObject'] = castObject;
-this['NULL'] = wrapPointer(0);
+Module['NULL'] = wrapPointer(0);
function destroy(obj) {
if (!obj['__destroy__']) throw 'Error: Cannot destroy object. (Did you create it yourself?)';
obj['__destroy__']();
+ // Remove from cache, so the object can be GC'd and refs added onto it released
+ if (obj.__class__ !== Object) {
+ delete obj.__class__.prototype.__cache__[obj.ptr];
+ } else {
+ delete Object__cache[obj.ptr];
+ }
}
-this['destroy'] = destroy;
+Module['destroy'] = destroy;
function compare(obj1, obj2) {
return obj1.ptr === obj2.ptr;
}
-this['compare'] = compare;
+Module['compare'] = compare;
function getPointer(obj) {
return obj.ptr;
}
-this['getPointer'] = getPointer;
+Module['getPointer'] = getPointer;
+
+function getClass(obj) {
+ return obj.__class__;
+}
+Module['getClass'] = getClass;
+
+function customizeVTable(object, replacementPairs) {
+ // Does not handle multiple inheritance
+
+ // Find out vtable size
+ var vTable = getValue(object.ptr, 'void*');
+ // This assumes our modification where we null-terminate vtables
+ var size = 0;
+ while (getValue(vTable + Runtime.QUANTUM_SIZE*size, 'void*')) {
+ size++;
+ }
+
+ // Prepare replacement lookup table and add replacements to FUNCTION_TABLE
+ // There is actually no good way to do this! So we do the following hack:
+ // We create a fake vtable with canary functions, to detect which actual
+ // function is being called
+ var vTable2 = _malloc(size*Runtime.QUANTUM_SIZE);
+ setValue(object.ptr, vTable2, 'void*');
+ var canaryValue;
+ var functions = FUNCTION_TABLE.length;
+ for (var i = 0; i < size; i++) {
+ var index = FUNCTION_TABLE.length;
+ (function(j) {
+ FUNCTION_TABLE.push(function() {
+ canaryValue = j;
+ });
+ })(i);
+ FUNCTION_TABLE.push(0);
+ setValue(vTable2 + Runtime.QUANTUM_SIZE*i, index, 'void*');
+ }
+ var args = [{ptr: 0}];
+ replacementPairs.forEach(function(pair) {
+ // We need the wrapper function that converts arguments to not fail. Keep adding arguments til it works.
+ while(1) {
+ try {
+ pair['original'].apply(object, args);
+ break;
+ } catch(e) {
+ args.push(args[0]);
+ }
+ }
+ pair.originalIndex = getValue(vTable + canaryValue*Runtime.QUANTUM_SIZE, 'void*');
+ });
+ FUNCTION_TABLE = FUNCTION_TABLE.slice(0, functions);
+
+ // Do the replacements
+
+ var replacements = {};
+ replacementPairs.forEach(function(pair) {
+ var replacementIndex = FUNCTION_TABLE.length;
+ FUNCTION_TABLE.push(pair['replacement']);
+ FUNCTION_TABLE.push(0);
+ replacements[pair.originalIndex] = replacementIndex;
+ });
+
+ // Copy and modify vtable
+ for (var i = 0; i < size; i++) {
+ var value = getValue(vTable + Runtime.QUANTUM_SIZE*i, 'void*');
+ if (value in replacements) value = replacements[value];
+ setValue(vTable2 + Runtime.QUANTUM_SIZE*i, value, 'void*');
+ }
+ return object;
+}
+Module['customizeVTable'] = customizeVTable;
''')
d