Merge remote-tracking branch 'upstream/master'

Conflicts:
	src/intertyper.js
	tests/runner.py
This commit is contained in:
max99x 2011-09-13 02:14:32 +03:00
Родитель 91e29b31f2 534cc7f058
Коммит c5e5c90cd1
13 изменённых файлов: 292 добавлений и 88 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -275,25 +275,27 @@ function analyzer(data) {
}
});
// Second pass over variables - notice when types are crossed by bitcast
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;
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 (!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];

Просмотреть файл

@ -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;

Просмотреть файл

@ -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',

Просмотреть файл

@ -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));

Просмотреть файл

@ -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

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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:

Просмотреть файл

@ -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')

Просмотреть файл

@ -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;
''')
def generate_wrapping_code(classname):
@ -411,7 +494,7 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
# For abstract base classes, add a function definition on top. There is no constructor
gen_js.write('\nfunction ' + generating_classname_head + ('(){ throw "%s is abstract!" }\n' % generating_classname_head) + generate_wrapping_code(generating_classname_head))
if export:
gen_js.write('''this['%s'] = %s;
gen_js.write('''Module['%s'] = %s;
''' % (generating_classname_head, generating_classname_head))
for method in clazz['final_methods'].itervalues():
@ -466,6 +549,8 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
return ([] if not need_self else [classname + ' * self']) + map(lambda i: args[i]['type'] + ' arg' + str(i), range(len(args)))
def justargs(args):
return map(lambda i: 'arg' + str(i), range(len(args)))
def justtypes(args): # note: this ignores 'self'
return map(lambda i: args[i]['type'], range(len(args)))
fullname = ('emscripten_bind_' + generating_classname + '__' + mname).replace('::', '__')
generating_classname_suffixed = generating_classname
@ -505,8 +590,7 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
gen_c.write(method['operator'])
else: # normal method
gen_c.write(''' %s%s%s(%s);''' % ('return ' if ret.replace(' ', '') != 'void' else '',
callprefix, actualmname, ', '.join(justargs(args)[:i])))
callprefix, actualmname, ', '.join(justargs(args)[:i])))
gen_c.write('\n')
gen_c.write('}')
else:
@ -564,6 +648,9 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge
print 'Maekin:', classname, generating_classname, mname, mname_suffixed
if constructor:
calls += '''
%s.prototype.__cache__[this.ptr] = this;
this.__class__ = %s;''' % (mname_suffixed, mname_suffixed)
if not dupe:
js_text = '''
function %s(%s) {
@ -580,7 +667,7 @@ function %s(%s) {
if export:
js_text += '''
this['%s'] = %s;
Module['%s'] = %s;
''' % (mname_suffixed, mname_suffixed)
else:
@ -675,6 +762,7 @@ struct EmscriptenEnsurer
{
EmscriptenEnsurer() {
// Actually use the binding functions, so DFE will not eliminate them
// FIXME: A negative side effect of this is that they take up space in FUNCTION_TABLE
int sum = 0;
void *seen = (void*)%s;
''' % c_funcs[0])

Просмотреть файл

@ -17,10 +17,14 @@ Example uses:
* With configure, do something like
RANLIB=PATH/emmaken.py AR=PATH/emmaken.py CXX=PATH/emmaken.py CC=PATH/emmaken.py ./configure [options]
EMMAKEN_JUST_CONFIGURE=1 RANLIB=PATH/emmaken.py AR=PATH/emmaken.py CXX=PATH/emmaken.py CC=PATH/emmaken.py ./configure [options]
where PATH is the path to this file.
EMMAKEN_JUST_CONFIGURE tells emmaken that it is being run in ./configure,
so it should relay everything to gcc/g++. You should not define that when
running make, of course.
* With CMake, the same command will work (with cmake instead of ./configure). You may also be
able to do the following in your CMakeLists.txt:
@ -53,20 +57,21 @@ import sys
import os
import subprocess
print >> sys.stderr, 'emmaken.py: ', ' '.join(sys.argv)
abspath = os.path.abspath(os.path.dirname(__file__))
def path_from_root(*pathelems):
return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + list(pathelems)))
exec(open(path_from_root('tools', 'shared.py'), 'r').read())
# If this is a CMake config, just do that
# If this is a configure-type thing, just do that
CONFIGURE_CONFIG = os.environ.get('EMMAKEN_JUST_CONFIGURE')
CMAKE_CONFIG = 'CMakeFiles/cmTryCompileExec.dir' in ' '.join(sys.argv)# or 'CMakeCCompilerId' in ' '.join(sys.argv)
if CMAKE_CONFIG:
if CONFIGURE_CONFIG or CMAKE_CONFIG:
compiler = 'g++' if 'CXXCompiler' in ' '.join(sys.argv) else 'gcc'
exit(os.execvp(compiler, [compiler] + sys.argv[1:]))
try:
print >> sys.stderr, 'emmaken.py: ', ' '.join(sys.argv)
#f=open('/dev/shm/tmp/waka.txt', 'a')
#f.write('Args: ' + ' '.join(sys.argv) + '\nCMake? ' + str(CMAKE_CONFIG) + '\n')
#f.close()
@ -97,7 +102,6 @@ try:
if len(sys.argv) == 2 and 'conftest' not in ' '.join(sys.argv): # Avoid messing with configure, see below too
# ranlib
os.execvp(LLVM_DIS, ['-show-annotations', sys.argv[1]])
sys.exit(0)
if len(sys.argv) == 1 or sys.argv[1] in ['x', 't']:
# noop ar
@ -116,7 +120,7 @@ try:
files.append(arg)
if arg.endswith('.c'):
use_cxx = False
if arg.endswith(('.c', '.cc', '.cpp')):
if arg.endswith(('.c', '.cc', '.cpp', '.dT')):
use_linker = False
if arg.endswith('.h'):
header = True
@ -130,8 +134,8 @@ try:
assert use_linker, 'Linker should be used in this case'
if use_linker:
call = LLVM_LINK
newargs = []
call = LLVM_LD
newargs = ['-disable-opt']
found_o = False
i = 0
while i < len(sys.argv)-1:
@ -163,6 +167,7 @@ try:
if not use_linker:
newargs.append('-c')
else:
print >> sys.stderr, 'Just copy.'
shutil.copy(sys.argv[-1], sys.argv[-2])
exit(0)

Просмотреть файл

@ -14,6 +14,7 @@ exec(open(CONFIG_FILE, 'r').read())
CLANG=os.path.expanduser(os.path.join(LLVM_ROOT, 'clang++'))
LLVM_LINK=os.path.join(LLVM_ROOT, 'llvm-link')
LLVM_LD=os.path.join(LLVM_ROOT, 'llvm-ld')
LLVM_OPT=os.path.expanduser(os.path.join(LLVM_ROOT, 'opt'))
LLVM_AS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-as'))
LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis'))
@ -69,7 +70,7 @@ def line_splitter(data):
def limit_size(string, MAX=80*20):
if len(string) < MAX: return string
return string[0:MAX] + '...'
return string[0:MAX/2] + '\n[..]\n' + string[-MAX/2:]
def pick_llvm_opts(optimization_level, optimize_size, allow_nonportable=False, use_aa=False):
opts = []