aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-02-21 09:55:01 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-02-21 09:55:01 -0800
commit282f297568fbdc7d347ef3cdf8a00324b39eace7 (patch)
treeaffa91349b69f1da2e91411a8bbcdf03082c4e26 /src
parent3c61023b189c412302981d6d029e21a58e9b428a (diff)
parente6f092d69f1806153571e6e808caea76f8bf5190 (diff)
Merge pull request #265 from adetaylor/polymorphic-exception-handling
Polymorphic exception handling.
Diffstat (limited to 'src')
-rw-r--r--src/intertyper.js13
-rw-r--r--src/jsifier.js5
-rw-r--r--src/library.js73
-rw-r--r--src/parseTools.js6
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;