aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/cases/gepoverflow.txt2
-rw-r--r--tests/gl_subdata.cpp141
-rw-r--r--tests/hello_libcxx_mod1.cpp9
-rwxr-xr-xtests/runner.py285
4 files changed, 417 insertions, 20 deletions
diff --git a/tests/cases/gepoverflow.txt b/tests/cases/gepoverflow.txt
index 90772c33..bd3091fd 100644
--- a/tests/cases/gepoverflow.txt
+++ b/tests/cases/gepoverflow.txt
@@ -1,2 +1,2 @@
-*5246502,5247072*
+*5246498,5247068*
*-514,56*
diff --git a/tests/gl_subdata.cpp b/tests/gl_subdata.cpp
new file mode 100644
index 00000000..d159b2b2
--- /dev/null
+++ b/tests/gl_subdata.cpp
@@ -0,0 +1,141 @@
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+#include <cmath>
+#include <iostream>
+#include <vector>
+extern "C" {
+#include <GL/gl.h>
+#include <GL/glut.h>
+}
+static const char vertex_shader[] =
+ "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "attribute float indices;\n"
+ "uniform sampler2D nodeInfo;\n"
+ "varying vec4 color;"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " float s = (indices + 0.5) / 512.; \n"
+ " vec4 v = texture2D(nodeInfo, vec2( s, 0.5));\n"
+ " gl_Position = vec4(v.x, v.y, 0.5, 1.);\n"
+ " gl_PointSize = v.z;\n"
+ " color = vec4(0.5 + v.w/2., 0.5 + 0.5 * v.w/2., 0.5, 1);\n"
+ "}\n";
+static const char fragment_shader[] =
+ "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "\n"
+ "varying vec4 color;\n"
+ "void main(void)\n"
+ "{\n"
+ " float dst = distance(vec2(0.5, 0.5), gl_PointCoord); \n"
+ " gl_FragColor = color;\n"
+ " if ( dst > 0.3) {"
+ " gl_FragColor = vec4(0., 0., 0.5, 0.2);\n"
+ "}\n"
+ "if ( dst > 0.5) discard;\n"
+ "}";
+struct NodeInfo { //structure that we want to transmit to our shaders
+ float x;
+ float y;
+ float s;
+ float c;
+};
+GLuint nodeTexture; //texture id used to bind
+GLuint nodeSamplerLocation; //shader sampler address
+GLuint indicesAttributeLocation; //shader attribute address
+GLuint indicesVBO; //Vertex Buffer Object Id;
+const int nbNodes = 512;
+NodeInfo data[nbNodes]; //our data that will be transmitted using float texture.
+double alpha = 0; //use to make a simple funny effect;
+static void updateFloatTexture() {
+ int count = 0;
+ for (float x=0; x < nbNodes; ++x ) {
+ data[count].x = 0.2*pow(cos(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * cos(alpha + x/nbNodes * 16. * M_PI);
+ data[count].y = 0.2*pow(sin(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * sin(alpha + x/nbNodes * 16. * M_PI);
+ data[count].s = (16. + 16. * cos(alpha + x/nbNodes * 32. * M_PI)) + 8.;// * fmod(x/nbNodes + alpha, 1.) + 5.;
+ data[count].c = 0.5 + 0.5 * sin(alpha + x/nbNodes * 32. * M_PI);
+ ++count;
+ }
+ glBindTexture(GL_TEXTURE_2D, nodeTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, nbNodes, 1, 0, GL_RGBA, GL_FLOAT, data);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glBindTexture(GL_TEXTURE_2D, NULL);
+ alpha -= 0.001;
+}
+static void glut_draw_callback(void) {
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glClearColor(1., 1., 1., 0.);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glActiveTexture(GL_TEXTURE0);
+ updateFloatTexture(); //we change the texture each time to create the effect (it is just for the test)
+ glBindTexture(GL_TEXTURE_2D, nodeTexture);
+ glUniform1i(nodeSamplerLocation, GL_TEXTURE0);
+ glEnableVertexAttribArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, indicesVBO);
+ glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);
+ glDrawArrays(GL_POINTS, 0, nbNodes);
+ glutSwapBuffers();
+}
+GLuint createShader(const char source[], int type) {
+ char msg[512];
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, (const GLchar**)(&source), NULL);
+ glCompileShader(shader);
+ glGetShaderInfoLog(shader, sizeof msg, NULL, msg);
+ std::cout << "Shader info: " << msg << std::endl;
+ return shader;
+}
+static void gl_init(void) {
+ GLuint program = glCreateProgram();
+ glAttachShader(program, createShader(vertex_shader , GL_VERTEX_SHADER));
+ glAttachShader(program, createShader(fragment_shader, GL_FRAGMENT_SHADER));
+ glLinkProgram(program);
+ char msg[512];
+ glGetProgramInfoLog(program, sizeof msg, NULL, msg);
+ std::cout << "info: " << msg << std::endl;
+ glUseProgram(program);
+ std::vector<float> elements(nbNodes);
+ int count = 0;
+ for (float x=0; x < nbNodes; ++x ) {
+ elements[count] = count;
+ ++count;
+ }
+ /*Create one texture to store all the needed information */
+ glGenTextures(1, &nodeTexture);
+ /* Store the vertices in a vertex buffer object (VBO) */
+ glGenBuffers(1, &indicesVBO);
+ glBindBuffer(GL_ARRAY_BUFFER, indicesVBO);
+ float zeroes[nbNodes];
+ memset(zeroes, 0, sizeof(zeroes));
+ glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(float), zeroes, GL_STATIC_DRAW);
+ for (int x = 0; x < nbNodes; x++) {
+ glBufferSubData(GL_ARRAY_BUFFER, x * sizeof(float), elements.size() * sizeof(float), &elements[x]);
+ }
+ /* Get the locations of the uniforms so we can access them */
+ nodeSamplerLocation = glGetUniformLocation(program, "nodeInfo");
+ glBindAttribLocation(program, 0, "indices");
+ //Enable glPoint size in shader, always enable in Open Gl ES 2.
+ glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ glEnable(GL_POINT_SPRITE);
+}
+int main(int argc, char *argv[]) {
+ glutInit(&argc, argv);
+ glutInitWindowSize(640, 480);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+ glutCreateWindow("Simple FLOAT Texture Test");
+ /* Set up glut callback functions */
+ glutDisplayFunc(glut_draw_callback );
+ gl_init();
+ glutMainLoop();
+ return 0;
+}
+
+
diff --git a/tests/hello_libcxx_mod1.cpp b/tests/hello_libcxx_mod1.cpp
new file mode 100644
index 00000000..2389b1ef
--- /dev/null
+++ b/tests/hello_libcxx_mod1.cpp
@@ -0,0 +1,9 @@
+#include <iostream>
+
+int main()
+{
+ std::cout << "hello, world!" << std::endl;
+ std::cout << "hello, world!" << std::endl;
+ return 0;
+}
+
diff --git a/tests/runner.py b/tests/runner.py
index b7e44c05..09fd7d49 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -970,7 +970,7 @@ m_divisor is 1091269979
Settings.PRECISE_I64_MATH = 0
self.do_run(src, 'unsigned')
code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
- assert 'goog.math.Long' not in code and 'jsbn' not in code, 'i64 precise math should not have been included if not asked for'
+ assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not asked for'
# Verify that even if we ask for precision, if it is not needed it is not included
Settings.PRECISE_I64_MATH = 1
@@ -994,7 +994,28 @@ m_divisor is 1091269979
'''
self.do_run(src, '*4903566027370624, 153236438355333*')
code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
- assert 'goog.math.Long' not in code and 'jsbn' not in code, 'i64 precise math should not have been included if not actually used'
+ assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not actually used'
+
+ # But if we force it to be included, it is. First, a case where we don't need it
+ Settings.PRECISE_I64_MATH = 2
+ self.do_run(open(path_from_root('tests', 'hello_world.c')).read(), 'hello')
+ code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
+ assert 'goog.math.Long' in code, 'i64 precise math should be included if forced'
+
+ # and now one where we do
+ self.do_run(r'''
+ #include <stdio.h>
+
+ int main( int argc, char ** argv )
+ {
+ unsigned long a = 0x60DD1695U;
+ unsigned long b = 0xCA8C4E7BU;
+ unsigned long long c = (unsigned long long)a * b;
+ printf( "c = %016llx\n", c );
+
+ return 0;
+ }
+ ''', 'c = 4ca38a6bd2973f97')
def test_i64_zextneg(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
@@ -1347,6 +1368,7 @@ c5,de,15,8a
def test_floatvars(self):
src = '''
#include <stdio.h>
+ #include <math.h>
int main()
{
float x = 1.234, y = 3.5, q = 0.00000001;
@@ -1354,6 +1376,8 @@ c5,de,15,8a
int z = x < y;
printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q);
+ printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3));
+
/*
// Rounding behavior
float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
@@ -1365,7 +1389,7 @@ c5,de,15,8a
return 0;
}
'''
- self.do_run(src, '*1,10,10.5,1,1.2340,0.00*')
+ self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\n')
def test_globaldoubles(self):
src = r'''
@@ -1429,6 +1453,24 @@ c5,de,15,8a
'''
self.do_run(src, '*3.14,-3.14,1,0,0,0,1,0,1,1,0,2,3,0.0,1.0,0.0,1.0*')
+ def test_erf(self):
+ src = '''
+ #include <math.h>
+ #include <stdio.h>
+ int main()
+ {
+ printf("%1.6f, %1.6f, %1.6f, %1.6f, %1.6f, %1.6f\\n",
+ erf(1.0),
+ erf(3.0),
+ erf(-1.0),
+ erfc(1.0),
+ erfc(3.0),
+ erfc(-1.5));
+ return 0;
+ }
+ '''
+ self.do_run(src, '0.842701, 0.999978, -0.842701, 0.157299, 0.000022, 1.966105')
+
def test_math_hyperbolic(self):
src = open(path_from_root('tests', 'hyperbolic', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read()
@@ -1948,6 +1990,52 @@ c5,de,15,8a
else:
self.do_run(src, 'second\nmain: 0\n')
+ def test_longjmp2(self):
+ src = r'''
+ #include <setjmp.h>
+ #include <stdio.h>
+
+ typedef struct {
+ jmp_buf* jmp;
+ } jmp_state;
+
+ void stack_manipulate_func(jmp_state* s, int level) {
+ jmp_buf buf;
+
+ printf("Entering stack_manipulate_func, level: %d\n", level);
+
+ if (level == 0) {
+ s->jmp = &buf;
+ if (setjmp(*(s->jmp)) == 0) {
+ printf("Setjmp normal execution path, level: %d\n", level);
+ stack_manipulate_func(s, level + 1);
+ } else {
+ printf("Setjmp error execution path, level: %d\n", level);
+ }
+ } else {
+ printf("Perform longjmp at level %d\n", level);
+ longjmp(*(s->jmp), 1);
+ }
+
+ printf("Exiting stack_manipulate_func, level: %d\n", level);
+ }
+
+ int main(int argc, char *argv[]) {
+ jmp_state s;
+ s.jmp = NULL;
+ stack_manipulate_func(&s, 0);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''Entering stack_manipulate_func, level: 0
+Setjmp normal execution path, level: 0
+Entering stack_manipulate_func, level: 1
+Perform longjmp at level 1
+Setjmp error execution path, level: 0
+Exiting stack_manipulate_func, level: 0
+''')
+
def test_exceptions(self):
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
@@ -2738,6 +2826,7 @@ c5,de,15,8a
// EMSCRIPTEN_COMMENT("hello from the source");
emscripten_run_script("Module.print('hello world' + '!')");
printf("*%d*\n", emscripten_run_script_int("5*20"));
+ printf("*%s*\n", emscripten_run_script_string("'five'+'six'"));
emscripten_run_script("_save_me_aimee()");
return 0;
}
@@ -2749,19 +2838,26 @@ def process(filename):
# TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src
'''
- self.do_run(src, 'hello world!\n*100*\nmann\n', post_build=check)
+ self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
def test_inlinejs(self):
src = r'''
#include <stdio.h>
+ double get() {
+ double ret = 0;
+ __asm __volatile__("12/3.3":"=a"(ret));
+ return ret;
+ }
+
int main() {
asm("Module.print('Inline JS is very cool')");
+ printf("%.2f\n", get());
return 0;
}
'''
- self.do_run(src, 'Inline JS is very cool')
+ self.do_run(src, 'Inline JS is very cool\n3.64')
def test_memorygrowth(self):
if Settings.USE_TYPED_ARRAYS == 0: return self.skip('memory growth is only supported with typed arrays')
@@ -4467,11 +4563,15 @@ Pass: 0.000012 0.000012''')
int x = sscanf("one %n two", "%s %n", word, &l);
printf("%d,%s,%d\n", x, word, l);
-
+ {
+ int a, b, c, count;
+ count = sscanf("12345 6789", "%d %n%d", &a, &b, &c);
+ printf("%i %i %i %i\n", count, a, b, c);
+ }
return 0;
}
'''
- self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4''')
+ self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4\n2 12345 6 6789\n''')
def test_sscanf_whitespace(self):
src = r'''
@@ -4521,7 +4621,22 @@ Pass: 0.000012 0.000012''')
self.do_run(src, '3\n123,1073741823,1125899906842620\n' +
'3\n-123,-1073741823,-1125899906842620\n')
-
+
+ def test_sscanf_4(self):
+ src = r'''
+ #include <stdio.h>
+
+ int main()
+ {
+ char pYear[16], pMonth[16], pDay[16], pDate[64];
+ printf("%d\n", sscanf("Nov 19 2012", "%s%s%s", pMonth, pDay, pYear));
+ printf("day %s, month %s, year %s \n", pDay, pMonth, pYear);
+ return(0);
+ }
+ '''
+
+ self.do_run(src, '3\nday 19, month Nov, year 2012');
+
def test_langinfo(self):
src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
@@ -6126,7 +6241,9 @@ def process(filename):
finally:
del os.environ['EMCC_DEBUG']
for debug in [1,2]:
- self.assertIdentical(open('release.js').read().replace('\n\n', '\n').replace('\n\n', '\n'), open('debug%d.js' % debug).read().replace('\n\n', '\n').replace('\n\n', '\n')) # EMCC_DEBUG=1 mode must not generate different code!
+ def clean(text):
+ return text.replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n')
+ self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code!
print >> sys.stderr, 'debug check %d passed too' % debug
try_delete(CANONICAL_TEMP_DIR)
@@ -7654,6 +7771,22 @@ f.close()
Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ def test_unaligned_memory_2(self):
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <string>
+ #include <stdio.h>
+
+ int main( int argc, char ** argv )
+ {
+ std::string testString( "Hello, World!" );
+
+ printf( "testString = %s\n", testString.c_str() );
+ return 0;
+ }
+ ''')
+ Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
+ self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
def test_l_link(self):
# Linking with -lLIBNAME and -L/DIRNAME should work
@@ -8100,6 +8233,33 @@ f.close()
output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate()
self.assertNotContained('Unresolved symbol: _something\n', output[1])
+ def test_toobig(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ #define BYTES 100*1024*1024
+
+ int main(int argc, char **argv) {
+ if (argc == 100) {
+ static char buf[BYTES];
+ static char buf2[BYTES];
+ for (int i = 0; i < BYTES; i++) {
+ buf[i] = i*i;
+ buf2[i] = i/3;
+ }
+ for (int i = 0; i < BYTES; i++) {
+ buf[i] = buf2[i/2];
+ buf2[i] = buf[i/3];
+ }
+ printf("%d\n", buf[10] + buf2[20]);
+ }
+ return 0;
+ }
+ ''')
+ output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate()[1]
+ assert 'Emscripten failed' in output, output
+ assert 'warning: very large fixed-size structural type' in output, output
+
def test_prepost(self):
open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
#include <stdio.h>
@@ -8203,7 +8363,7 @@ f.close()
(path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(),
['simplifyExpressionsPre', 'optimizeShiftsAggressive']),
# Make sure that optimizeShifts handles functions with shift statements.
- (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3.js')).read(),
+ (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(),
['optimizeShiftsAggressive']),
(path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(),
['registerize']),
@@ -8222,6 +8382,17 @@ f.close()
assert 'foo.o: ' in output, '-%s failed to produce the right output: %s' % (opt, output)
assert 'error' not in err, 'Unexpected stderr: ' + err
+ def test_chunking(self):
+ if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
+ if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores')
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ output, err = Popen(['python', EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1'], stdout=PIPE, stderr=PIPE).communicate()
+ assert 'phase 2 working on 3 chunks' in err, err
+ assert 'splitting up js optimization into 2 chunks' in err, err
+ finally:
+ del os.environ['EMCC_DEBUG']
+
def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1
try_delete(os.path.join(self.get_dir(), 'test'))
shutil.copytree(path_from_root('tests', 'scons'), os.path.join(self.get_dir(), 'test'))
@@ -9477,6 +9648,9 @@ elif 'browser' in str(sys.argv):
def test_float_tex(self):
self.btest('float_tex.cpp', reference='float_tex.png')
+ def test_subdata(self):
+ self.btest('gl_subdata.cpp', reference='float_tex.png')
+
def test_runtimelink(self):
main, supp = self.setup_runtimelink_test()
@@ -9978,6 +10152,8 @@ elif 'sanity' in str(sys.argv):
assert os.path.exists(CONFIG_FILE), 'To run these tests, we need a (working!) %s file to already exist' % EM_CONFIG
+ assert not os.environ.get('EMCC_DEBUG'), 'do not run sanity checks in debug mode!'
+
shutil.copyfile(CONFIG_FILE, CONFIG_FILE + '_backup')
def restore():
shutil.copyfile(CONFIG_FILE + '_backup', CONFIG_FILE)
@@ -10210,10 +10386,11 @@ fi
self.assertContained(SANITY_MESSAGE, output)
# but with EMCC_DEBUG=1 we should check
- assert not os.environ.get('EMCC_DEBUG'), 'do not run sanity checks in debug mode!'
- os.environ['EMCC_DEBUG'] = '1'
- output = self.check_working(EMCC)
- del os.environ['EMCC_DEBUG']
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ output = self.check_working(EMCC)
+ finally:
+ del os.environ['EMCC_DEBUG']
self.assertContained(SANITY_MESSAGE, output)
output = self.check_working(EMCC)
self.assertNotContained(SANITY_MESSAGE, output)
@@ -10270,8 +10447,8 @@ fi
assert not os.path.exists(EMCC_CACHE)
try:
- emcc_debug = os.environ.get('EMCC_DEBUG')
os.environ['EMCC_DEBUG'] ='1'
+ self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
# Building a file that doesn't need cached stuff should not trigger cache generation
output = self.do([EMCC, path_from_root('tests', 'hello_world.cpp')])
@@ -10287,8 +10464,6 @@ fi
ll_name1 = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-2-ll.ll')
ll_name2 = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-3-ll.ll')
- self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
-
# Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time
for filename, libname in [('hello_malloc.cpp', 'dlmalloc'), ('hello_libcxx.cpp', 'libcxx')]:
for i in range(3):
@@ -10321,8 +10496,7 @@ fi
print i, 'll metadata should be removed in -O1 and O2 by default', ll[-300:]
assert False
finally:
- if emcc_debug:
- os.environ['EMCC_DEBUG'] = emcc_debug
+ del os.environ['EMCC_DEBUG']
# Manual cache clearing
assert os.path.exists(EMCC_CACHE)
@@ -10350,6 +10524,79 @@ fi
assert os.path.exists(RELOOPER) == (i >= 2), 'have relooper on O2: ' + output
assert ('L2 : do {' in open('a.out.js').read()) == (i >= 2), 'reloop code on O2: ' + output
+ def test_jcache(self):
+ PRE_LOAD_MSG = 'loading pre from jcache'
+ PRE_SAVE_MSG = 'saving pre to jcache'
+ FUNC_CHUNKS_LOAD_MSG = ' funcchunks from jcache'
+ FUNC_CHUNKS_SAVE_MSG = ' funcchunks to jcache'
+ JSFUNC_CHUNKS_LOAD_MSG = 'jsfuncchunks from jcache'
+ JSFUNC_CHUNKS_SAVE_MSG = 'jsfuncchunks to jcache'
+
+ restore()
+ Cache.erase()
+
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
+ if not os.path.exists(self.working_dir): os.makedirs(self.working_dir)
+
+ assert not os.path.exists(JCache.get_cachename('emscript_files'))
+
+ srcs = {}
+ used_jcache = False
+
+ for args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected in [
+ ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
+ (['--jcache'], 'hello_world_loop.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
+ # new
+ ([], 'hello_world.cpp', False, False, False, False, False, False, []),
+ (['--jcache'], 'hello_world.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_world.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_world.cpp', False, False, False, False, False, False, []),
+ # go back to old file, experience caching
+ (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
+ # new, large file
+ ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
+ (['--jcache'], 'hello_malloc.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_malloc.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
+ # new, huge file
+ ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('2 chunks', '3 chunks')),
+ (['--jcache'], 'hello_libcxx.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_libcxx.cpp', False, False, False, False, False, False, []),
+ # finally, build a file close to the previous, to see that some chunks are found in the cache and some not
+ (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, False, []), # win on pre, mix on funcs, fail on jsfuncs
+ (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, False, True, False, True, []),
+ ]:
+ print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected
+ self.clear()
+ out, err = Popen(['python', EMCC, '-O2', '--closure', '0', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
+ errtail = err.split('emcc invocation')[-1]
+ self.assertContained('hello, world!', run_js('a.out.js'), errtail)
+ assert (PRE_SAVE_MSG in err) == expect_pre_save, errtail
+ assert (PRE_LOAD_MSG in err) == expect_pre_load, errtail
+ assert (FUNC_CHUNKS_SAVE_MSG in err) == expect_funcs_save, errtail
+ assert (FUNC_CHUNKS_LOAD_MSG in err) == expect_funcs_load, errtail
+ assert (JSFUNC_CHUNKS_SAVE_MSG in err) == expect_jsfuncs_save, errtail
+ assert (JSFUNC_CHUNKS_LOAD_MSG in err) == expect_jsfuncs_load, errtail
+ for expect in expected: assert expect in err, expect + ' ? ' + errtail
+ curr = open('a.out.js').read()
+ if input_file not in srcs:
+ srcs[input_file] = curr
+ else:
+ open('/home/alon/Dev/emscripten/a', 'w').write(srcs[input_file])
+ open('/home/alon/Dev/emscripten/b', 'w').write(curr)
+ assert abs(len(curr)/float(len(srcs[input_file]))-1)<0.01, 'contents may shift in order, but must remain the same size %d vs %d' % (len(curr), len(srcs[input_file])) + '\n' + errtail
+ used_jcache = used_jcache or ('--jcache' in args)
+ assert used_jcache == os.path.exists(JCache.get_cachename('emscript_files'))
+ #print >> sys.stderr, errtail
+
+ finally:
+ del os.environ['EMCC_DEBUG']
+
else:
raise Exception('Test runner is confused: ' + str(sys.argv))