1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
diff --git a/src/parseTools.js b/src/parseTools.js
index 9786460..fb4be9f 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -205,26 +205,57 @@ function isFunctionDef(token, out) {
function isPossiblyFunctionType(type) {
// A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite.
var len = type.length;
- return type[len-2] == ')' && type[len-1] == '*';
+ return type[len-2] == ')' && type[len-1] == '*' && type.indexOf('(') > 0;
}
function isFunctionType(type, out) {
if (!isPossiblyFunctionType(type)) return false;
type = type.replace(/"[^"]+"/g, '".."');
- var parts;
// hackish, but quick splitting of function def parts. this must be fast as it happens a lot
- if (type[0] != '[') {
- parts = type.split(' ');
- } else {
- var index = type.search(']');
- index += type.substr(index).search(' ');
- parts = [type.substr(0, index), type.substr(index+1)];
- }
+ var parts = type.split(' ');
if (pointingLevels(type) !== 1) return false;
var text = removeAllPointing(parts.slice(1).join(' '));
if (!text) return false;
- if (out) out.returnType = parts[0];
- return isType(parts[0]) && isFunctionDef({ text: text, item: tokenize(text.substr(1, text.length-2), true) }, out);
+ if (!isType(parts[0])) return false;
+ var level = 0;
+ var chunks = [];
+ var currStart = 0;
+ for (var i = 0; i < type.length; i++) {
+ var curr = type[i];
+ if (curr == '(') {
+ level++;
+ if (level == 1) {
+ chunks.push(type.substring(currStart, i));
+ currStart = i+1;
+ }
+ } else if (curr == ')') {
+ level--;
+ if (level == 0) {
+ curr = type.substring(currStart, i);
+ if (curr == '') curr = '$'; // make sure inside of () stays valid
+ chunks.push(curr);
+ currStart = i+1;
+ }
+ }
+ }
+//printErr('pre chunks ' + JSON.stringify(chunks));
+ chunks = chunks.map(function(chunk) { return chunk.replace(/ /g, '') })
+ .filter(function(chunk) { return chunk.length > 0 })
+ .map(function(chunk) { return chunk.replace(/\$/g, ' ') });
+//printErr('post chunks ' + JSON.stringify(chunks));
+ switch (chunks.length) {
+ case 2: { // e.g. void (i32,i32)
+ if (out) out.returnType = chunks[0]; // TODO: add cache, with this as the value
+ return isFunctionDef({ text: '(' + chunks[1] + ')', item: tokenize(chunks[1], true) }, out);
+ }
+ case 4: { // e.g. void (i32)* (i32, i32) (i.e., returns void (i32)*!)
+ if (chunks[2] != '*') return false;
+ if (out) out.returnType = chunks[0] + ' ' + chunks[1];
+ return isFunctionDef({ text: '(' + chunks[1] + ')', item: tokenize(chunks[1], true) }) &&
+ isFunctionDef({ text: '(' + chunks[2] + ')', item: tokenize(chunks[2], true) }, out);
+ }
+ }
+ return false;
}
var isTypeCache = {}; // quite hot, optimize as much as possible
diff --git a/tests/runner.py b/tests/runner.py
index 842daca..312541f 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -2860,6 +2860,35 @@ Exiting setjmp function, level: 0, prev_jmp: -1
'''
self.do_run(src, 'fn2(-5) = 5, fn(10) = 3.16')
+ def test_funcptrfunc(self):
+ src = r'''
+ #include <stdio.h>
+
+/*
+define internal fastcc void ()* @sqlite3OsDlSym(%struct.sqlite3_vfs* %pVfs, i8* %pHdle, i8* %zSym) nounwind {
+ %1 = getelementptr inbounds %struct.sqlite3_vfs* %pVfs, i32 0, i32 12
+ %2 = load void ()* (%struct.sqlite3_vfs*, i8*, i8*)** %1, align 4
+ %3 = tail call void ()* (%struct.sqlite3_vfs*, i8*, i8*)* %2(%struct.sqlite3_vfs* %pVfs, i8* %pHdle, i8* %zSym) nounwind
+ ret void ()* %3
+}
+*/
+
+ typedef void (*funcptr)(int, int);
+ typedef funcptr (*funcptrfunc)(int);
+
+ funcptr __attribute__ ((noinline)) getIt(int x) {
+ return (funcptr)x;
+ }
+
+ int main(int argc, char **argv)
+ {
+ funcptrfunc fpf = argc < 100 ? getIt : NULL;
+ printf("*%p*\n", fpf(argc));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0x1*')
+
def test_emptyclass(self):
if self.emcc_args is None: return self.skip('requires emcc')
src = '''
|