diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-02-21 09:55:01 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-02-21 09:55:01 -0800 |
commit | 282f297568fbdc7d347ef3cdf8a00324b39eace7 (patch) | |
tree | affa91349b69f1da2e91411a8bbcdf03082c4e26 /src | |
parent | 3c61023b189c412302981d6d029e21a58e9b428a (diff) | |
parent | e6f092d69f1806153571e6e808caea76f8bf5190 (diff) |
Merge pull request #265 from adetaylor/polymorphic-exception-handling
Polymorphic exception handling.
Diffstat (limited to 'src')
-rw-r--r-- | src/intertyper.js | 13 | ||||
-rw-r--r-- | src/jsifier.js | 5 | ||||
-rw-r--r-- | src/library.js | 73 | ||||
-rw-r--r-- | src/parseTools.js | 6 |
4 files changed, 91 insertions, 6 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 91ad15eb..cfb12331 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -728,11 +728,22 @@ function intertyper(data, sidePass, baseLineNums) { this.forwardItem(item, 'Reintegrator'); } }); - // 'landingpad' - just a stub implementation + // 'landingpad' substrate.addActor('Landingpad', { processItem: function(item) { item.intertype = 'landingpad'; item.type = item.tokens[1].text; + item.catchables = []; + var catchIdx = findTokenText(item, "catch"); + if (catchIdx != -1) { + do { + var nextCatchIdx = findTokenTextAfter(item, "catch", catchIdx+1); + if (nextCatchIdx == -1) + nextCatchIdx = item.tokens.length; + item.catchables.push(parseLLVMSegment(item.tokens.slice(catchIdx+2, nextCatchIdx))); + catchIdx = nextCatchIdx; + } while (catchIdx != item.tokens.length); + } Types.needAnalysis[item.type] = 0; this.forwardItem(item, 'Reintegrator'); } diff --git a/src/jsifier.js b/src/jsifier.js index b3701112..bc827135 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -988,9 +988,8 @@ function JSify(data, functionsOnly, givenFunctions) { } }); makeFuncLineActor('landingpad', function(item) { - // Just a stub - return '{ f0: ' + makeGetValue('_llvm_eh_exception.buf', '0', 'void*') + - ', f1:' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + ' }'; + var catchTypeArray = item.catchables.map(finalizeLLVMParameter).join(','); + return '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + ',[' + catchTypeArray +'])'; }); makeFuncLineActor('load', function(item) { var value = finalizeLLVMParameter(item.pointer); diff --git a/src/library.js b/src/library.js index 0d756608..cda318d7 100644 --- a/src/library.js +++ b/src/library.js @@ -4374,6 +4374,7 @@ LibraryManager.library = { __cxa_guard_release: function() {}, __cxa_guard_abort: function() {}, + _ZTVN10__cxxabiv119__pointer_type_infoE: [0], // is a pointer _ZTVN10__cxxabiv117__class_type_infoE: [1], // no inherited classes _ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes @@ -4402,7 +4403,7 @@ LibraryManager.library = { __cxa_free_exception: function(ptr) { return _free(ptr); }, - __cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv'], + __cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], __cxa_throw: function(ptr, type, destructor) { #if EXCEPTION_DEBUG print('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + new Error().stack); @@ -4486,6 +4487,74 @@ LibraryManager.library = { __gxx_personality_v0: function() { }, + // Finds a suitable catch clause for when an exception is thrown. + // In normal compilers, this functionality is handled by the C++ + // 'personality' routine. This is passed a fairly complex structure + // relating to the context of the exception and makes judgements + // about how to handle it. Some of it is about matching a suitable + // catch clause, and some of it is about unwinding. We already handle + // unwinding using 'if' blocks around each function, so the remaining + // functionality boils down to picking a suitable 'catch' block. + // We'll do that here, instead, to keep things simpler. + + __cxa_find_matching_catch__deps: ['__cxa_does_inherit'], + __cxa_find_matching_catch: function(thrown, throwntype, typeArray) { + // If throwntype is a pointer, this means a pointer has been + // thrown. When a pointer is thrown, actually what's thrown + // is a pointer to the pointer. We'll dereference it. + if (throwntype != 0) { + var throwntypeInfoAddr= {{{ makeGetValue('throwntype', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}}; + var throwntypeInfo= {{{ makeGetValue('throwntypeInfoAddr', '0', '*') }}}; + if (throwntypeInfo == 0) + thrown = {{{ makeGetValue('thrown', '0', '*') }}}; + } + // The different catch blocks are denoted by different types. + // Due to inheritance, those types may not precisely match the + // type of the thrown object. Find one which matches, and + // return the type of the catch block which should be called. + for (var i = 0; i < typeArray.length; i++) { + if (___cxa_does_inherit(typeArray[i], throwntype)) + return { 'f0':thrown, 'f1':typeArray[i]}; + } + // Shouldn't happen unless we have bogus data in typeArray + // or encounter a type for which emscripten doesn't have suitable + // typeinfo defined. Best-efforts match just in case. + return {'f0':thrown,'f1':throwntype}; + }, + + // Recursively walks up the base types of 'possibilityType' + // to see if any of them match 'definiteType'. + + __cxa_does_inherit: function(definiteType, possibilityType) { + if (possibilityType == 0 || possibilityType == definiteType) + return true; + var possibility_type_infoAddr = {{{ makeGetValue('possibilityType', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}}; + var possibility_type_info = {{{ makeGetValue('possibility_type_infoAddr', '0', '*') }}}; + switch (possibility_type_info) { + case 0: // possibility is a pointer + // See if definite type is a pointer + var definite_type_infoAddr = {{{ makeGetValue('definiteType', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}}; + var definite_type_info = {{{ makeGetValue('definite_type_infoAddr', '0', '*') }}}; + if (definite_type_info == 0) { + // Also a pointer; compare base types of pointers + var defPointerBaseAddr = definiteType+{{{ Runtime.QUANTUM_SIZE*2 }}}; + var defPointerBaseType = {{{ makeGetValue('defPointerBaseAddr', '0', '*') }}}; + var possPointerBaseAddr = possibilityType+{{{ Runtime.QUANTUM_SIZE*2 }}}; + var possPointerBaseType = {{{ makeGetValue('possPointerBaseAddr', '0', '*') }}}; + return ___cxa_does_inherit(defPointerBaseType, possPointerBaseType); + } else + return false; // one pointer and one non-pointer + case 1: // class with no base class + return false; + case 2: // class with base class + var parentTypeAddr = possibilityType + {{{ Runtime.QUANTUM_SIZE*2 }}}; + var parentType = {{{ makeGetValue('parentTypeAddr', '0', '*') }}}; + return ___cxa_does_inherit(definiteType, parentType); + default: + return false; // some unencountered type + } + }, + // 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. @@ -4503,6 +4572,8 @@ LibraryManager.library = { _ZTIc: [0], // type_info for void. _ZTIv: [0], + // type_info for void*. + _ZTIPv: [0], llvm_uadd_with_overflow_i32: function(x, y) { return { diff --git a/src/parseTools.js b/src/parseTools.js index d3cb7795..c1eff803 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -227,7 +227,11 @@ function getTokenIndexByText(tokens, text) { } function findTokenText(item, text) { - for (var i = 0; i < item.tokens.length; i++) { + return findTokenTextAfter(item, text, 0); +} + +function findTokenTextAfter(item, text, startAt) { + for (var i = startAt; i < item.tokens.length; i++) { if (item.tokens[i].text == text) return i; } return -1; |