Merge branch 'master' into llvm-svn

This commit is contained in:
Alon Zakai 2011-09-15 20:09:18 -07:00
Родитель ce07f2aa77 734b1450b5
Коммит 4203afeb1a
8 изменённых файлов: 344 добавлений и 21 удалений

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

@ -209,6 +209,28 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
var constant = null;
if (item.external) {
// Import external global variables from the library if available.
var shortident = item.ident.slice(1);
if (LibraryManager.library[shortident] &&
LibraryManager.library[shortident].length &&
!BUILD_AS_SHARED_LIB) {
var val = LibraryManager.library[shortident];
var padding;
if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
padding = [item.type].concat(zeros(getNativeFieldSize(item.type)));
} else {
padding = makeEmptyStruct(item.type);
}
var padded = val.concat(padding.slice(val.length));
var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, 'ALLOC_STATIC', item.type) + ';'
if (LibraryManager.library[shortident + '__postset']) {
js += '\n' + LibraryManager.library[shortident + '__postset'];
}
ret.push({
intertype: 'GlobalVariablePostSet',
JS: js
});
}
return ret;
} else {
function needsPostSet(value) {
@ -723,6 +745,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
var ret = '(function() { try { __THREW__ = false; return '
+ call_ + ' '
+ '} catch(e) { '
+ 'if (typeof e != "number") throw e; '
+ 'if (ABORT) throw e; __THREW__ = true; '
+ (EXCEPTION_DEBUG ? 'print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
+ 'return null } })(); if (!__THREW__) { ' + branch
@ -806,10 +829,11 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
var argsTypes = [];
var varargs = [];
var varargsTypes = [];
var useJSArgs = (ident.slice(1) + '__jsargs') in LibraryManager.library;
params.forEach(function(param, i) {
var val = finalizeParam(param);
if (!func || !func.hasVarArgs || i < func.numParams-1) {
if (!func || !func.hasVarArgs || i < func.numParams-1 || useJSArgs) {
args.push(val);
argsTypes.push(param.type);
} else {
@ -823,7 +847,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
varargs = varargs.map(function(vararg, i) { return vararg === 0 ? 0 : indexizeFunctions(vararg, varargsTypes[i]) });
if (func && func.hasVarArgs) {
if (func && func.hasVarArgs && !useJSArgs) {
if (varargs.length === 0) {
varargs = [0];
varargsTypes = ['i32'];

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

@ -255,7 +255,7 @@ LibraryManager.library = {
xhr.open('GET', obj.url, false);
// Some hints to the browser that we want binary data.
xhr.responseType = 'arraybuffer';
if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
if (xhr.overrideMimeType) {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
@ -316,7 +316,7 @@ LibraryManager.library = {
// Command line.
result = readline();
}
if (!result) return null;
if (!result) result = '';
input.cache = intArrayFromString(result + '\n', true);
}
return input.cache.shift();
@ -2112,6 +2112,7 @@ LibraryManager.library = {
ftruncate64: 'ftruncate',
__01open64_: 'open',
__01lseek64_: 'lseek',
__01truncate64_: 'truncate',
__01ftruncate64_: 'ftruncate',
// TODO: Check if any other aliases are needed.
@ -3092,6 +3093,7 @@ LibraryManager.library = {
vsscanf: 'sscanf',
fopen64: 'fopen',
__01fopen64_: 'fopen',
__01freopen64_: 'freopen',
__01fseeko64_: 'fseek',
__01ftello64_: 'ftell',
__01tmpfile64_: 'tmpfile',
@ -3598,6 +3600,11 @@ LibraryManager.library = {
return String_len(ptr);
},
// TODO: Implement when we have real unicode support.
mblen: function() {
return 1;
},
strspn: function(pstr, pset) {
var str = String_copy(pstr, true);
var set = String_copy(pset);
@ -3622,6 +3629,14 @@ LibraryManager.library = {
} while ({{{ makeGetValue('psrc', 'i-1', 'i8') }}} != 0);
return pdest;
},
stpcpy: function(pdest, psrc) {
var i = 0;
do {
{{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8') }}}
i ++;
} while ({{{ makeGetValue('psrc', 'i-1', 'i8') }}} != 0);
return pdest + i - 1;
},
strncpy: function(pdest, psrc, num) {
var padding = false, curr;
@ -3992,25 +4007,75 @@ LibraryManager.library = {
return 1;
},
// Exceptions - minimal support, only (...) for now (no actual exception objects can be caught)
// Exceptions
__cxa_allocate_exception: function(size) {
return _malloc(size); // warning: leaked
return _malloc(size);
},
__cxa_throw: function(ptr, data, dunno) {
__cxa_free_exception: function(ptr) {
return _free(ptr);
},
__cxa_throw__deps: ['llvm_eh_exception'],
__cxa_throw: function(ptr, type, destructor) {
#if EXCEPTION_DEBUG
print('Compiled code throwing an exception, ' + [ptr,data,dunno] + ', at ' + new Error().stack);
print('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + new Error().stack);
#endif
{{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}}
{{{ makeSetValue('_llvm_eh_exception.buf', '4', 'type', 'void*') }}}
{{{ makeSetValue('_llvm_eh_exception.buf', '8', 'destructor', 'void*') }}}
throw ptr;
},
llvm_eh_exception: function() {
return 'code-generated exception: ' + (new Error().stack);
__cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'],
__cxa_rethrow: function() {
___cxa_end_catch.rethrown = true;
throw {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
},
llvm_eh_selector: function(exception, personality, num) {
llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);',
llvm_eh_exception: function() {
return {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
},
llvm_eh_selector__jsargs: true,
llvm_eh_selector: function(unused_exception_value, personality/*, varargs*/) {
var type = {{{ makeGetValue('_llvm_eh_exception.buf', '4', 'void*') }}}
for (var i = 2; i < arguments.length; i++) {
if (arguments[i] == type) return type;
}
return 0;
},
__cxa_begin_catch: function(ptr) {
llvm_eh_typeid_for: function(type) {
return type;
},
__cxa_end_catch: function(ptr) {
_Unwind_Resume_or_Rethrow: function(ptr) {
throw ptr;
},
__cxa_begin_catch: function(ptr) {
return ptr;
},
__cxa_end_catch__deps: ['llvm_eh_exception', '__cxa_free_exception'],
__cxa_end_catch: function() {
if (___cxa_end_catch.rethrown) {
___cxa_end_catch.rethrown = false;
return;
}
// Clear state flag.
__THREW__ = false;
// Clear type.
{{{ makeSetValue('_llvm_eh_exception.buf', '4', '0', 'void*') }}}
// Call destructor if one is registered then clear it.
var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', '8', 'void*') }}};
if (destructor) {
FUNCTION_TABLE[destructor](ptr);
{{{ makeSetValue('_llvm_eh_exception.buf', '8', '0', 'i32') }}}
}
// Free ptr if it isn't null.
if (ptr) {
___cxa_free_exception(ptr);
{{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}
}
},
__cxa_get_exception_ptr__deps: ['llvm_eh_exception'],
__cxa_get_exception_ptr: function(ptr) {
return ptr;
},
__cxa_call_unexpected: function(exception) {
@ -4018,9 +4083,29 @@ LibraryManager.library = {
throw exception;
},
terminate: '__cxa_call_unexpected',
__gxx_personality_v0: function() {
},
// RTTI hacks for exception handling, defining type_infos for common types.
// The values are dummies. We simply use the addresses of these statically
// allocated variables as unique identifiers.
// type_info for int.
_ZTIi: [0],
// type_info for long.
_ZTIl: [0],
// type_info for long long.
_ZTIx: [0],
// type_info for float.
_ZTIf: [0],
// type_info for double.
_ZTId: [0],
// type_info for char.
_ZTIc: [0],
// type_info for void.
_ZTIv: [0],
llvm_umul_with_overflow_i32: function(x, y) {
return {
f0: x*y,
@ -4686,6 +4771,28 @@ LibraryManager.library = {
// sys/time.h
// ==========================================================================
__timespec_struct_layout: Runtime.generateStructInfo(null, '%struct.timespec'),
// TODO: Implement these for real.
clock_gettime__deps: ['__timespec_struct_layout'],
clock_gettime: function(clk_id, tp) {
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
{{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', '0', 'i32') }}}
{{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
return 0;
},
clock_settime: function(clk_id, tp) {
// int clock_settime(clockid_t clk_id, const struct timespec *tp);
// Nothing.
return 0;
},
clock_getres__deps: ['__timespec_struct_layout'],
clock_getres: function(clk_id, res) {
// int clock_getres(clockid_t clk_id, struct timespec *res);
{{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}}
{{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
return 0;
},
// TODO: Implement remaining functions.
// http://pubs.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html
gettimeofday: function(ptr) {
@ -4756,6 +4863,23 @@ LibraryManager.library = {
// TODO
return 0;
},
sigemptyset: function(set) {
// int sigemptyset(sigset_t *set);
// TODO: Implement for real; don't hardcode offsets.
{{{ makeSetValue('set', '0', '0', 'i32') }}}
{{{ makeSetValue('set', '4', '0', 'i32') }}}
{{{ makeSetValue('set', '8', '0', 'i32') }}}
{{{ makeSetValue('set', '12', '0', 'i32') }}}
return 0;
},
sigfillset: 'sigemptyset',
sigdelset: 'sigemptyset',
sigaction: function(set) {
// int sigemptyset(sigset_t *set);
// TODO: Implement for real.
return 0;
},
sigprocmask: 'sigaction',
__libc_current_sigrtmin: function() {
return 0;
},
@ -5166,6 +5290,24 @@ LibraryManager.library = {
__errno_location: function() {
return ___setErrNo.ret;
},
// ==========================================================================
// sys/resource.h
// ==========================================================================
// TODO: Implement for real.
__rlimit_struct_layout: Runtime.generateStructInfo(null, '%struct.rlimit'),
getrlimit__deps: ['__rlimit_struct_layout'],
getrlimit: function(resource, rlp) {
// int getrlimit(int resource, struct rlimit *rlp);
{{{ makeSetValue('rlp', '___rlimit_struct_layout.rlim_cur', '-1', 'i32') }}} // RLIM_INFINITY
{{{ makeSetValue('rlp', '___rlimit_struct_layout.rlim_max', '-1', 'i32') }}} // RLIM_INFINITY
return 0;
},
setrlimit: function(resource, rlp) {
// int setrlimit(int resource, const struct rlimit *rlp)
return 0;
},
__01getrlimit64_: 'getrlimit',
// ==========================================================================
// pthread.h (stubs for mutexes only - no thread support yet!)

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

@ -1050,7 +1050,7 @@ function getGetElementPtrIndexes(item) {
}
curr = 0;
}
type = typeData ? typeData.fields[curr] : '';
type = typeData && typeData.fields[curr] ? typeData.fields[curr] : '';
});
var ret = indexes[0];
for (var i = 1; i < indexes.length; i++) {

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

@ -321,7 +321,7 @@ function setValue(ptr, value, type) {
default: abort('invalid type for setValue: ' + type);
}
}
this['setValue'] = setValue;
Module['setValue'] = setValue;
// Parallel to setValue.
@ -339,7 +339,7 @@ function getValue(ptr, type) {
}
return null;
}
this['getValue'] = getValue;
Module['getValue'] = getValue;
// Allocates memory for some data and initializes it properly.

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

@ -0,0 +1,50 @@
*CREATING A FOO
*CREATING A BAR
*CREATING A QUUX
start
throwing ExFooInstance
*COPYING A FOO
*COPYING A FOO
outer catch foo: 11
*DESTROYING A FOO (11)
*DESTROYING A FOO (11)
throwing ExBarInstance
*COPYING A BAR
*COPYING A BAR
inner re-throw: 22
*DESTROYING A BAR (22)
outer catch bar-ref: 22
*DESTROYING A BAR (22)
throwing ExQuuxInstance
*COPYING A QUUX
*COPYING A QUUX
inner catch quux: 33
*DESTROYING A QUUX (33)
*DESTROYING A QUUX (33)
throwing 42
outer catch int: 42
throwing NULL
outer catch-all
not throwing
end
*DESTROYING A QUUX (33)
*DESTROYING A BAR (22)
*DESTROYING A FOO (11)

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

@ -0,0 +1,91 @@
#include <stdio.h>
class ExFoo {
public:
int x;
ExFoo(int x) { this->x = x; printf("*CREATING A FOO\n"); }
ExFoo(const ExFoo& other) { x=other.x; printf("*COPYING A FOO\n"); }
~ExFoo() { printf("*DESTROYING A FOO (%d)\n", x); }
} ExFooInstance(11);
class ExBar {
public:
int x;
ExBar(int x) { this->x = x; printf("*CREATING A BAR\n"); }
ExBar(const ExBar& other) { x=other.x; printf("*COPYING A BAR\n"); }
~ExBar() { printf("*DESTROYING A BAR (%d)\n", x); }
} ExBarInstance(22);
class ExQuux {
public:
int x;
ExQuux(int x) { this->x = x; printf("*CREATING A QUUX\n"); }
ExQuux(const ExQuux& other) { x=other.x; printf("*COPYING A QUUX\n"); }
~ExQuux() { printf("*DESTROYING A QUUX (%d)\n", x); }
} ExQuuxInstance(33);
// NOTE: Throwing pointers and polymorphic matching not supported.
// class ExChild : public ExQuux {
// public:
// ExChild(int x) : ExQuux(x) { printf("*CREATING A CHILD\n"); }
// ExChild(const ExChild& other) : ExQuux(x) { x=other.x; printf("*COPYING CHILD\n"); }
// ~ExChild() { printf("*DESTROYING A CHILD (%d)\n", x); }
// } ExChildInstance(44);
void magic(int which) {
try {
switch (which) {
case 0:
printf(" throwing ExFooInstance\n");
throw ExFooInstance;
case 1:
printf(" throwing ExBarInstance\n");
throw ExBarInstance;
case 2:
printf(" throwing ExQuuxInstance\n");
throw ExQuuxInstance;
// NOTE: Throwing pointers and polymorphic matching not supported.
// case 3:
// printf(" throwing ExQuux ptr\n");
// throw &ExQuuxInstance;
// case 4:
// printf(" throwing ExChildInstance\n");
// throw ExChildInstance;
case 5:
printf(" throwing 42\n");
throw 42;
case 6:
printf(" throwing NULL\n");
throw (void*)0;
case 7:
printf(" not throwing\n");
}
} catch (ExQuux e1) {
printf("inner catch quux: %d\n", e1.x);
} catch (ExBar e2) {
printf("inner re-throw: %d\n", e2.x);
throw;
}
}
int main() {
printf("start\n\n\n");
for (int i = 0; i < 8; i++) {
try {
magic(i);
} catch (ExFoo e1) {
printf("outer catch foo: %d\n", e1.x);
} catch (ExBar& e2) {
printf("outer catch bar-ref: %d\n", e2.x);
// NOTE: Throwing pointers and polymorphic matching not supported.
// } catch (ExQuux& e3) {
// printf("outer catch quux-ref: %d\n", e3.x);
// } catch (ExQuux* e4) {
// printf("outer catch quux-ptr: %d\n", e4->x);
} catch (int e5) {
printf("outer catch int: %d\n", e5);
} catch (...) {
printf("outer catch-all\n");
}
printf("\n\n");
}
printf("end\n");
return 0;
}

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

@ -180,7 +180,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', 'FAST_MEMORY']:
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
@ -994,6 +994,13 @@ if 'benchmark' not in str(sys.argv):
DISABLE_EXCEPTIONS = 1
self.do_test(src, 'Compiled code throwing an exception')
def test_typed_exceptions(self):
global SAFE_HEAP; SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
global EXCEPTION_DEBUG; EXCEPTION_DEBUG = 0 # Messes up expected output.
src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read()
expected = open(path_from_root('tests', 'exceptions', 'output.txt'), 'r').read()
self.do_test(src, expected)
def test_class(self):
src = '''
#include <stdio.h>

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

@ -442,8 +442,17 @@ function customizeVTable(object, replacementPairs) {
FUNCTION_TABLE.push(0);
setValue(vTable2 + Runtime.QUANTUM_SIZE*i, index, 'void*');
}
var args = [{ptr: 0}];
replacementPairs.forEach(function(pair) {
pair.original.call(object);
// 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);
@ -453,7 +462,7 @@ function customizeVTable(object, replacementPairs) {
var replacements = {};
replacementPairs.forEach(function(pair) {
var replacementIndex = FUNCTION_TABLE.length;
FUNCTION_TABLE.push(pair.replacement);
FUNCTION_TABLE.push(pair['replacement']);
FUNCTION_TABLE.push(0);
replacements[pair.originalIndex] = replacementIndex;
});
@ -485,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():
@ -658,7 +667,7 @@ function %s(%s) {
if export:
js_text += '''
this['%s'] = %s;
Module['%s'] = %s;
''' % (mname_suffixed, mname_suffixed)
else: