aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormax99x <max99x@gmail.com>2011-07-08 08:33:45 +0300
committermax99x <max99x@gmail.com>2011-07-08 08:39:31 +0300
commit1bd1893888ebe52b6e7676becddbecc577f0e169 (patch)
tree00bc29bdf7a393b28aca2704c4de39c9ca538604
parentcfbdf063100f6c7c8405f582d03034d6d791f642 (diff)
* Added support for automatically determining llvm-gcc/clang data layout in emscripten.py.
* Added a dlmalloc linking test. * Fixed double-evaling of JSON in emscripten.py when --dlmalloc is passed.
-rwxr-xr-xemscripten.py52
-rw-r--r--tests/dlmalloc_test.c41
-rw-r--r--tests/runner.py16
3 files changed, 94 insertions, 15 deletions
diff --git a/emscripten.py b/emscripten.py
index fc0f63cc..c11f1cfd 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -9,7 +9,12 @@ import tempfile
import tools.shared as shared
+# Temporary files that should be deleted once teh program is finished.
TEMP_FILES_TO_CLEAN = []
+# The data layout used by llvm-gcc (as opposed to clang).
+GCC_DATA_LAYOUT = ('target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16'
+ '-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64'
+ '-v128:128:128-a0:0:64-f80:32:32-f128:128:128-n8:16:32"')
def path_from_root(*target):
@@ -98,21 +103,48 @@ def link(*objects):
return out.name
-def compile_malloc():
- """Compiles dlmalloc to LLVM bitcode and returns the path to the .bc file."""
+def compile_malloc(compiler):
+ """Compiles dlmalloc to LLVM bitcode.
+
+ Args:
+ compiler: The compiler command to use, a path to either clang or llvm-gcc.
+
+ Returns:
+ The path to the compiled dlmalloc as an LLVM bitcode (.bc) file.
+ """
src = path_from_root('src', 'dlmalloc.c')
out = get_temp_file('.bc')
- clang = shared.to_cc(shared.CLANG)
- include_dir = '-I' + path_from_root('src', 'include')
- command = [clang, '-c', '-g', '-emit-llvm', '-m32', '-o-', include_dir, src]
+ includes = '-I' + path_from_root('src', 'include')
+ command = [compiler, '-c', '-g', '-emit-llvm', '-m32', '-o-', includes, src]
ret = subprocess.call(command, stdout=out)
out.close()
if ret != 0: raise RuntimeError('Could not compile dlmalloc.')
return out.name
+def determine_compiler(filepath):
+ """Determines whether a given file uses llvm-gcc or clang data layout.
+
+ Args:
+ filepath: The .bc or .ll file containing the bitcode/assembly to test.
+
+ Returns:
+ The path to the compiler, either llvm-gcc or clang.
+ """
+ assembly = open(disassemble(filepath)).read()
+ is_gcc = GCC_DATA_LAYOUT in assembly
+ return shared.to_cc(shared.LLVM_GCC if is_gcc else shared.CLANG)
+
+
def has_annotations(filepath):
- """Tests whether an assembly file contains annotations."""
+ """Tests whether an assembly file contains annotations.
+
+ Args:
+ filepath: The .ll file containing the assembly to check.
+
+ Returns:
+ Whether the provided file is valid assembly and has annotations.
+ """
return filepath.endswith('.ll') and '[#uses=' in open(filepath).read()
@@ -139,7 +171,9 @@ def main(args):
# Construct a final linked and disassembled file.
if args.dlmalloc or args.optimize or not has_annotations(args.infile):
args.infile = assemble(args.infile)
- if args.dlmalloc: args.infile = link(args.infile, compile_malloc())
+ if args.dlmalloc:
+ malloc = compile_malloc(determine_compiler(args.infile))
+ args.infile = link(args.infile, malloc)
if args.optimize: args.infile = optimize(args.infile)
args.infile = disassemble(args.infile)
@@ -151,10 +185,10 @@ def main(args):
# Adjust sign correction for dlmalloc.
if args.dlmalloc:
- CORRECT_SIGNS = int(settings.get('CORRECT_SIGNS', 0))
+ CORRECT_SIGNS = settings.get('CORRECT_SIGNS', 0)
if CORRECT_SIGNS in (0, 2):
path = path_from_root('src', 'dlmalloc.c')
- old_lines = json.loads(settings.get('CORRECT_SIGNS_LINES', '[]'))
+ old_lines = settings.get('CORRECT_SIGNS_LINES', [])
line_nums = [4816, 4191, 4246, 4199, 4205, 4235, 4227]
lines = old_lines + [path + ':' + str(i) for i in line_nums]
settings['CORRECT_SIGNS'] = 2
diff --git a/tests/dlmalloc_test.c b/tests/dlmalloc_test.c
new file mode 100644
index 00000000..6fbc45ab
--- /dev/null
+++ b/tests/dlmalloc_test.c
@@ -0,0 +1,41 @@
+// Emscripten tests
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int main(int ac, char **av) {
+ int NUM = ac > 1 ? atoi(av[1]) : 0;
+ int REPS = ac > 2 ? atoi(av[2]) : 0;
+ int c1 = 0, c2 = 0;
+ for (int x = 0; x < REPS; x++) {
+ char* allocations[NUM];
+ for (int i = 0; i < NUM/2; i++) {
+ allocations[i] = (char*)malloc((11*i)%1024 + x);
+ assert(allocations[i]);
+ if (i > 10 && i%4 == 1 && allocations[i-10]) {
+ free(allocations[i-10]);
+ allocations[i-10] = NULL;
+ }
+ }
+ for (int i = NUM/2; i < NUM; i++) {
+ allocations[i] = (char*)malloc(1024*(i+1));
+ assert(allocations[i]);
+ if (i > 10 && i%4 != 1 && allocations[i-10]) {
+ free(allocations[i-10]);
+ allocations[i-10] = NULL;
+ }
+ }
+ char* first = allocations[0];
+ for (int i = 0; i < NUM; i++) {
+ if (allocations[i]) {
+ free(allocations[i]);
+ }
+ }
+ char *last = (char*)malloc(512); // should be identical, as we free'd it all
+ char *newer = (char*)malloc(512); // should be different
+ c1 += first == last;
+ c2 += first == newer;
+ }
+ printf("*%d,%d*\n", c1, c2);
+}
diff --git a/tests/runner.py b/tests/runner.py
index 84b358fd..04856b8b 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -120,7 +120,7 @@ class RunnerCore(unittest.TestCase):
self.do_llvm_dis(filename)
# Build JavaScript code from source code
- def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None):
+ def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None, extra_emscripten_args=[]):
# Copy over necessary files for compiling the source
if main_file is None:
f = open(filename, 'w')
@@ -169,9 +169,9 @@ class RunnerCore(unittest.TestCase):
# Finalize
self.prep_ll_test(filename, filename + '.o', build_ll_hook=build_ll_hook)
- self.do_emscripten(filename, output_processor)
+ self.do_emscripten(filename, output_processor, extra_args=extra_emscripten_args)
- def do_emscripten(self, filename, output_processor=None, append_ext=True):
+ def do_emscripten(self, filename, output_processor=None, append_ext=True, extra_args=[]):
# Run Emscripten
exported_settings = {}
for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY']:
@@ -181,7 +181,7 @@ class RunnerCore(unittest.TestCase):
except:
pass
settings = ['%s=%s' % (k, json.dumps(v)) for k, v in exported_settings.items()]
- compiler_output = timeout_run(Popen([EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js', '-s'] + settings, stdout=PIPE, stderr=STDOUT), TIMEOUT, 'Compiling')
+ compiler_output = timeout_run(Popen([EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js', '-s'] + settings + extra_args, stdout=PIPE, stderr=STDOUT), TIMEOUT, 'Compiling')
# Detect compilation crashes and errors
if compiler_output is not None and 'Traceback' in compiler_output and 'in test_' in compiler_output: print compiler_output; assert 0
@@ -234,7 +234,7 @@ if 'benchmark' not in sys.argv:
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
## Does a complete test - builds, runs, checks output, etc.
- def do_test(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None):
+ def do_test(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
#print 'Running test:', inspect.stack()[1][3].replace('test_', ''), '[%s,%s,%s]' % (COMPILER.split(os.sep)[-1], 'llvm-optimizations' if LLVM_OPTS else '', 'reloop&optimize' if RELOOP else '')
if force_c or (main_file is not None and main_file[-2:]) == '.c':
basename = 'src.c'
@@ -245,7 +245,7 @@ if 'benchmark' not in sys.argv:
filename = os.path.join(dirname, basename)
if not no_build:
self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
- build_ll_hook=build_ll_hook)
+ build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args)
if post_build is not None:
post_build(filename + '.o.js')
@@ -2683,6 +2683,10 @@ if 'benchmark' not in sys.argv:
shutil.copy(filename + '.o.js', os.path.join(self.get_dir(), 'src.cpp.o.js'))
self.do_test(None, 'test\n', no_build=True)
+ def test_dlmalloc_linked(self):
+ src = open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
+ self.do_test(src, '*1,0*', ['200', '1'], extra_emscripten_args=['-m'])
+
def test_linespecific(self):
global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g']