aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jsifier.js14
-rw-r--r--src/modules.js3
-rw-r--r--system/include/libcxx/ostream6
-rw-r--r--tests/runner.py9
-rw-r--r--tools/eliminator/eliminator-test-output.js18
-rw-r--r--tools/eliminator/eliminator-test.js20
-rw-r--r--tools/eliminator/eliminator.coffee26
-rw-r--r--tools/shared.py8
8 files changed, 81 insertions, 23 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index bd432001..d8ed589e 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -411,7 +411,6 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
funcs: {},
seen: {},
processItem: function(item) {
- if (IGNORED_FUNCTIONS.indexOf(item.ident) >= 0) return null;
if (this.seen[item.__uid__]) return null;
if (item.intertype == 'function') {
this.funcs[item.ident] = item;
@@ -435,6 +434,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
// We have this function all reconstructed, go and finalize it's JS!
+ if (IGNORED_FUNCTIONS.indexOf(func.ident) >= 0) return null;
+
func.JS = '\nfunction ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n';
if (PROFILE) {
@@ -931,7 +932,14 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
generated = generated.concat(itemsDict.function).concat(data.unparsedFunctions);
- if (!mainPass) return generated.map(function(item) { return item.JS }).join('\n');
+ if (!mainPass) {
+ Functions.allIdents = Functions.allIdents.concat(itemsDict.function.map(function(func) {
+ return func.ident;
+ }).filter(function(func) {
+ return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
+ }));
+ return generated.map(function(item) { return item.JS }).join('\n');
+ }
// We are ready to print out the data, but must do so carefully - we are
// dealing with potentially *huge* strings. Convenient replacements and
@@ -967,6 +975,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
print(Functions.generateIndexing()); // done last, as it may rely on aliases set in postsets
print(postParts[1]);
print(shellParts[1]);
+ // Print out some useful metadata (for additional optimizations later, like the eliminator)
+ print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + JSON.stringify(Functions.allIdents) + '\n');
return null;
}
diff --git a/src/modules.js b/src/modules.js
index 3b370878..f04731f8 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -228,6 +228,9 @@ var Functions = {
// All functions that will be implemented in this file
implementedFunctions: null,
+ // All the function idents seen so far
+ allIdents: [],
+
indexedFunctions: [0, 0], // Start at a non-0 (even, see below) value
// Mark a function as needing indexing, and returns the index
diff --git a/system/include/libcxx/ostream b/system/include/libcxx/ostream
index c70f3c15..c7d294e2 100644
--- a/system/include/libcxx/ostream
+++ b/system/include/libcxx/ostream
@@ -204,7 +204,6 @@ protected:
basic_ostream() {} // extension, intentially does not initialize
};
-/*
template <class _CharT, class _Traits>
class _LIBCPP_VISIBLE basic_ostream<_CharT, _Traits>::sentry
{
@@ -1286,9 +1285,8 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
use_facet<ctype<_CharT> >(__os.getloc()).widen('1'));
}
-extern template class basic_ostream<char>;
-extern template class basic_ostream<wchar_t>;
-*/
+//extern template class basic_ostream<char>; /* XXX EMScripten */
+//extern template class basic_ostream<wchar_t>; /* XXX EMScripten */
_LIBCPP_END_NAMESPACE_STD
diff --git a/tests/runner.py b/tests/runner.py
index 8da2c8dd..e0362cd0 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -163,6 +163,13 @@ class RunnerCore(unittest.TestCase):
def run_native(self, filename, args):
Popen([filename+'.native'] + args, stdout=PIPE, stderr=STDOUT).communicate()[0]
+ def assertIdentical(self, x, y):
+ if x != y:
+ raise Exception("Expected to have '%s' == '%s', diff:\n\n%s" % (
+ limit_size(x), limit_size(y),
+ limit_size(''.join([a.rstrip()+'\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')]))
+ ))
+
def assertContained(self, value, string):
if type(value) is not str: value = value() # lazy loading
if type(string) is not str: string = string()
@@ -4178,7 +4185,7 @@ TT = %s
input = open(path_from_root('tools', 'eliminator', 'eliminator-test.js')).read()
expected = open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read()
output = Popen([COFFEESCRIPT, VARIABLE_ELIMINATOR], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(input)[0]
- self.assertEquals(output, expected)
+ self.assertIdentical(expected, output)
else:
# Benchmarks. Run them with argument |benchmark|. To run a specific test, do
diff --git a/tools/eliminator/eliminator-test-output.js b/tools/eliminator/eliminator-test-output.js
index 2324124e..b7a983cc 100644
--- a/tools/eliminator/eliminator-test-output.js
+++ b/tools/eliminator/eliminator-test-output.js
@@ -5,7 +5,7 @@ function f() {
HEAP[123] = (GLOB[1] + 1) / 2;
}
-var g = (function(a1, a2) {
+function g(a1, a2) {
var a = 1;
var c = a * 2 - 1;
@@ -39,7 +39,7 @@ var g = (function(a1, a2) {
unquoted: 3,
4: 5
};
-});
+}
function h() {
var out;
bar(hello);
@@ -91,3 +91,17 @@ function py() {
var $8 = HEAP[__PyThreadState_Current] + 12;
HEAP[$8] = $7;
}
+function otherPy() {
+ var $4 = HEAP[__PyThreadState_Current];
+ var $5 = $4 + 12;
+ var $7 = HEAP[$5] + 1;
+ var $8 = $4 + 12;
+ HEAP[$8] = $7;
+}
+var anon = (function(x) {
+ var $4 = HEAP[__PyThreadState_Current];
+ var $5 = $4 + 12;
+ var $7 = HEAP[$5] + 1;
+ var $8 = $4 + 12;
+ HEAP[$8] = $7;
+});
diff --git a/tools/eliminator/eliminator-test.js b/tools/eliminator/eliminator-test.js
index 8a364c0a..681b6cf7 100644
--- a/tools/eliminator/eliminator-test.js
+++ b/tools/eliminator/eliminator-test.js
@@ -5,7 +5,7 @@ function f() {
var z = y / 2;
HEAP[123] = z;
}
-var g = function (a1, a2) {
+function g(a1, a2) {
var a = 1;
var b = a * 2;
var c = b - 1;
@@ -39,7 +39,7 @@ var g = function (a1, a2) {
unquoted: 3,
4: 5
};
-};
+}
function h() {
var out;
bar(hello);
@@ -91,3 +91,19 @@ function py() {
var $8 = $4 + 12;
HEAP[$8] = $7;
}
+function otherPy() {
+ var $4 = HEAP[__PyThreadState_Current];
+ var $5 = $4 + 12;
+ var $7 = HEAP[$5] + 1;
+ var $8 = $4 + 12;
+ HEAP[$8] = $7;
+}
+var anon = function(x) {
+ var $4 = HEAP[__PyThreadState_Current];
+ var $5 = $4 + 12;
+ var $7 = HEAP[$5] + 1;
+ var $8 = $4 + 12;
+ HEAP[$8] = $7;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py"]
+
diff --git a/tools/eliminator/eliminator.coffee b/tools/eliminator/eliminator.coffee
index c07e5974..c6de8690 100644
--- a/tools/eliminator/eliminator.coffee
+++ b/tools/eliminator/eliminator.coffee
@@ -20,6 +20,10 @@
uglify = require 'uglify-js'
fs = require 'fs'
+# Functions which have been generated by Emscripten. We optimize only those.
+generatedFunctions = []
+GENERATED_FUNCTIONS_MARKER = '// EMSCRIPTEN_GENERATED_FUNCTIONS:'
+
# Maximum number of uses to consider a variable not worth eliminating.
MAX_USES = 3
@@ -79,6 +83,8 @@ traverse = (node, callback) ->
# function/defun node and call run() to apply the optimization (in-place).
class Eliminator
constructor: (func) ->
+ @ident = func[1]
+
# The statements of the function to analyze.
@body = func[3]
@@ -107,7 +113,7 @@ class Eliminator
# @returns: The number of variables eliminated, or undefined if skipped.
run: ->
# Our optimization does not account for closures.
- if @hasClosures @body then return undefined
+ if not @isGenerated() then return undefined
@calculateBasicVarStats()
@analyzeInitialValues()
@@ -128,16 +134,8 @@ class Eliminator
return eliminated
# Determines if a function is Emscripten-generated.
- hasClosures: ->
- closureFound = false
-
- traverse @body, (node, type) ->
- if type in ['defun', 'function', 'with']
- closureFound = true
- return false
- return undefined
-
- return closureFound
+ isGenerated: ->
+ return @ident in generatedFunctions
# Runs the basic variable scan pass. Fills the following member variables:
# isLocal
@@ -337,6 +335,12 @@ class Eliminator
main = ->
# Get the parse tree.
src = fs.readFileSync('/dev/stdin').toString()
+
+ throw 'Cannot identify generated functions' if GENERATED_FUNCTIONS_MARKER in src
+ generatedFunctionsLine = src.split('\n').filter (line) ->
+ return line.indexOf(GENERATED_FUNCTIONS_MARKER) == 0
+ generatedFunctions = eval(generatedFunctionsLine[0].replace(GENERATED_FUNCTIONS_MARKER, ''))
+
ast = uglify.parser.parse src
# Run the eliminator on all functions.
diff --git a/tools/shared.py b/tools/shared.py
index 7cd0fcb8..d5629b50 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -238,6 +238,12 @@ class Building:
except:
old_dir = None
os.chdir(project_dir)
+ generated_libs = map(lambda lib: os.path.join(project_dir, lib), generated_libs)
+ #for lib in generated_libs:
+ # try:
+ # os.unlink(lib) # make sure compilation completed successfully
+ # except:
+ # pass
env = os.environ.copy()
env['RANLIB'] = env['AR'] = env['CXX'] = env['CC'] = env['LIBTOOL'] = EMMAKEN
env['EMMAKEN_COMPILER'] = Building.COMPILER
@@ -253,7 +259,7 @@ class Building:
Popen(make + make_args, stdout=open(os.path.join(output_dir, 'make_'), 'w'),
stderr=open(os.path.join(output_dir, 'make_err'), 'w'), env=env).communicate()[0]
bc_file = os.path.join(project_dir, 'bc.bc')
- Building.link(map(lambda lib: os.path.join(project_dir, lib), generated_libs), bc_file)
+ Building.link(generated_libs, bc_file)
if cache is not None:
cache[cache_name] = open(bc_file, 'rb').read()
if old_dir: