aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-03-10 14:21:42 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-03-10 14:21:42 -0700
commitf8066edde43495c5ca6b869ff37f99a8290f30b5 (patch)
tree5005028e01e5115e83d71feeee0e2702fd5e8ee5
parent8be82c04408cab6519d3ed58305465ae97ca9da3 (diff)
function pointer support in PGO
-rw-r--r--src/modules.js2
-rwxr-xr-xtests/runner.py74
2 files changed, 51 insertions, 25 deletions
diff --git a/src/modules.js b/src/modules.js
index 797d4d83..e78b294f 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -291,7 +291,7 @@ var Functions = {
var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x';
assert(sig, ident);
if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact
- tables[sig][this.indexedFunctions[ident]] = ident;
+ tables[sig][this.indexedFunctions[ident]] = ident in DEAD_FUNCTIONS ? '0' : ident;
}
var generated = false;
var wrapped = {};
diff --git a/tests/runner.py b/tests/runner.py
index 61fb582a..b2bacb1b 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -7675,7 +7675,32 @@ def process(filename):
def test_pgo(self):
if Settings.ASM_JS: return self.skip('PGO does not work in asm mode')
- src = r'''
+ def run_all(name, src):
+ print name
+ def test(expected, args=[], no_build=False):
+ self.do_run(src, expected, args=args, no_build=no_build)
+ return open(self.in_dir('src.cpp.o.js')).read()
+
+ # Sanity check that it works and the dead function is emitted
+ js = test('*9*')
+ assert 'function _unused(' in js
+
+ # Run with PGO, see that unused is true to its name
+ Settings.PGO = 1
+ test("*9*\n-s DEAD_FUNCTIONS='[\"_unused\"]'")
+ Settings.PGO = 0
+
+ # Kill off the dead function, still works and it is not emitted
+ Settings.DEAD_FUNCTIONS = ['_unused']
+ js = test('*9*')
+ assert 'function _unused(' not in js
+ Settings.DEAD_FUNCTIONS = []
+
+ # Run the same code with argc that uses the dead function, see abort
+ test(('ReferenceError: _unused is not defined', 'is not a function'), args=['a', 'b'], no_build=True)
+
+ # Normal stuff
+ run_all('normal', r'''
#include <stdio.h>
extern "C" {
int used(int x) {
@@ -7691,30 +7716,31 @@ def process(filename):
printf("*%d*\n", argc == 3 ? unused(argv[0][0] + 1024) : used(argc + 1555));
return 0;
}
- '''
-
- def test(expected, args=[], no_build=False):
- self.do_run(src, expected, args=args, no_build=no_build)
- return open(self.in_dir('src.cpp.o.js')).read()
-
- # Sanity check that it works and the dead function is emitted
- js = test('*9*')
- assert 'function _unused(' in js
-
- # Run with PGO, see that unused is true to its name
- Settings.PGO = 1
- test("*9*\n-s DEAD_FUNCTIONS='[\"_unused\"]'")
- Settings.PGO = 0
-
- # Kill off the dead function, still works and it is not emitted
- Settings.DEAD_FUNCTIONS = ['_unused']
- js = test('*9*')
- assert 'function _unused(' not in js
-
- # Run the same code with argc that uses the dead function, see abort
- test('ReferenceError: _unused is not defined', args=['a', 'b'], no_build=True)
+ ''')
- # TODO: function pointers
+ # Call by function pointer
+ run_all('function pointers', r'''
+ #include <stdio.h>
+ extern "C" {
+ int used(int x) {
+ if (x == 0) return -1;
+ return used(x/3) + used(x/17) + x%5;
+ }
+ int unused(int x) {
+ if (x == 0) return -1;
+ return unused(x/4) + unused(x/23) + x%7;
+ }
+ }
+ typedef int (*ii)(int);
+ int main(int argc, char **argv) {
+ ii pointers[256];
+ for (int i = 0; i < 256; i++) {
+ pointers[i] = (i == 3) ? unused : used;
+ }
+ printf("*%d*\n", pointers[argc](argc + 1555));
+ return 0;
+ }
+ ''')
def test_scriptaclass(self):
if self.emcc_args is None: return self.skip('requires emcc')