emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.78k stars 3.3k forks source link

libjpeg doesn't work for progressive jpegs #446

Closed bompo closed 12 years ago

bompo commented 12 years ago

I tried to build the libjpeg release 8d with emscripten and the newest llvm release (3.1). If I build libjpeg with clang and convert a jpeg via the command line command "djpeg -output output.bin test.jpg" everything works fine for normal and progressive jpegs. Normal jpegs also working with the compiled emscripten version but progressive jpegs don't work. :/

The following error occurs if I try to decompress a progressive jpeg with the non optimized version:

FUNCTION_TABLE[$23] is not a function
http://localhost:8000/src.cpp.o.nonOptimized.js
Line 34247
var $43=FUNCTION_TABLE[$23]($25, $32, $39, $42, 1); //@line 259 "/tmp/emscripten_test_default_S32UFI/jdcoefct.c"

This is the corresponding line in jdcoefct.c

259: buffer[ci] = (*cinfo->mem->access_virt_barray)

I tried to compile libjpeg with LINKABLE and unoptimized flags but that doesn't help. :/

Here are the online test cases: normal jpg works: http://dl.dropbox.com/u/39448/diplom/libjpeg/test.html progressive jpg (throws error): http://dl.dropbox.com/u/39448/diplom/libjpeg/testp.html and the source code: http://dl.dropbox.com/u/39448/diplom/libjpeg.zip

As everything works with the clang compiled version this seems to be a emscripten error...

kripken commented 12 years ago

What commands would I use to compile the source into a native and JS build, so I can debug this?

bompo commented 12 years ago

Clang

./configure

replace CC (180) and CPP (183) with "clang"

make
./djpeg -output output.bin testp.jpg


Emscripten

emconfigure ./configure
make
/home/bompo/emscripten/emcc cdjpeg.o djpeg.o jaricom.o jcapimin.o jcapistd.o jcarith.o jccoefct.o jccolor.o jcdctmgr.o jchuff.o jcinit.o jcmainct.o jcmarker.o jcmaster.o jcomapi.o jcparam.o jcprepct.o jcsample.o jctrans.o jdapimin.o jdapistd.o jdarith.o jdatadst.o jdatasrc.o jdcoefct.o jdcolor.o jddctmgr.o jdhuff.o jdinput.o jdmainct.o jdmarker.o jdmaster.o jdmerge.o jdpostct.o jdsample.o jdtrans.o jerror.o jfdctflt.o jfdctfst.o jfdctint.o jidctflt.o jidctfst.o jidctint.o jmemmgr.o jmemnobs.o jquant1.o jquant2.o jutils.o rdbmp.o rdcolmap.o rdgif.o rdppm.o rdrle.o rdswitch.o rdtarga.o transupp.o wrbmp.o wrgif.o wrppm.o wrrle.o wrtarga.o -o ../../djpeg.js

wrap djpeg.js in a function: add the following code at the top of the js file

function readjpeg(data) {
 var Module = {};
 Module.arguments = [];
 var print = function(){};

and close the file at the bottom:

}

replace the pre run additions with

 
//prestuff
FS.init();
FS.root.write = true;
FS.createDataFile('/', 'input.jpg', data, true, false);

run(['-outfile', 'output.bin', 'input.jpg'])

return FS.root.contents['output.bin'].contents;

comment line 1403 and 1404 otherwise the js file complains with "Uncaught exit(0) called, at Error"

include the js file in the test.html / testp.html

kripken commented 12 years ago

Those instructions are a little complex, since to debug I might need to rebuild several times. Any chance you can make it easier, for example build scripts (both for js and native builds, for comparison)?

bompo commented 12 years ago

Sorry, here is a simpler compile process. I repacked the source code here: https://docs.google.com/open?id=0B5xMq2ROTC6KSG44d3haWS1pakU

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

./configure
make
gcc djpeg.o cdjpeg.o jaricom.o jcapimin.o jcapistd.o jcarith.o jccoefct.o jccolor.o jcdctmgr.o jchuff.o jcinit.o jcmainct.o jcmarker.o jcmaster.o jcomapi.o jcparam.o jcprepct.o jcsample.o jctrans.o jdapimin.o jdapistd.o jdarith.o jdatadst.o jdatasrc.o jdcoefct.o jdcolor.o jddctmgr.o jdhuff.o jdinput.o jdmainct.o jdmarker.o jdmaster.o jdmerge.o jdpostct.o jdsample.o jdtrans.o jerror.o jfdctflt.o jfdctfst.o jfdctint.o jidctflt.o jidctfst.o jidctint.o jmemmgr.o jmemnobs.o jquant1.o jquant2.o jutils.o rdbmp.o rdcolmap.o rdgif.o rdppm.o rdrle.o rdswitch.o rdtarga.o transupp.o wrbmp.o wrgif.o wrppm.o wrrle.o wrtarga.o -o djpeg

# works
./djpeg -bmp testimg.jpg > testimg.bmp

# works
./djpeg -bmp testimgp.jpg > testimgp.bmp


clang version 3.1 (tags/RELEASE_31/final)

CXX=clang CC=clang ./configure
make
clang djpeg.o cdjpeg.o jaricom.o jcapimin.o jcapistd.o jcarith.o jccoefct.o jccolor.o jcdctmgr.o jchuff.o jcinit.o jcmainct.o jcmarker.o jcmaster.o jcomapi.o jcparam.o jcprepct.o jcsample.o jctrans.o jdapimin.o jdapistd.o jdarith.o jdatadst.o jdatasrc.o jdcoefct.o jdcolor.o jddctmgr.o jdhuff.o jdinput.o jdmainct.o jdmarker.o jdmaster.o jdmerge.o jdpostct.o jdsample.o jdtrans.o jerror.o jfdctflt.o jfdctfst.o jfdctint.o jidctflt.o jidctfst.o jidctint.o jmemmgr.o jmemnobs.o jquant1.o jquant2.o jutils.o rdbmp.o rdcolmap.o rdgif.o rdppm.o rdrle.o rdswitch.o rdtarga.o transupp.o wrbmp.o wrgif.o wrppm.o wrrle.o wrtarga.o -o djpeg

# works
./djpeg -bmp testimg.jpg > testimg.bmp

# works
./djpeg -bmp testimgp.jpg > testimgp.bmp


emscripten

emconfigure ./configure
emmake make
emcc djpeg.o cdjpeg.o jaricom.o jcapimin.o jcapistd.o jcarith.o jccoefct.o jccolor.o jcdctmgr.o jchuff.o jcinit.o jcmainct.o jcmarker.o jcmaster.o jcomapi.o jcparam.o jcprepct.o jcsample.o jctrans.o jdapimin.o jdapistd.o jdarith.o jdatadst.o jdatasrc.o jdcoefct.o jdcolor.o jddctmgr.o jdhuff.o jdinput.o jdmainct.o jdmarker.o jdmaster.o jdmerge.o jdpostct.o jdsample.o jdtrans.o jerror.o jfdctflt.o jfdctfst.o jfdctint.o jidctflt.o jidctfst.o jidctint.o jmemmgr.o jmemnobs.o jquant1.o jquant2.o jutils.o rdbmp.o rdcolmap.o rdgif.o rdppm.o rdrle.o rdswitch.o rdtarga.o transupp.o wrbmp.o wrgif.o wrppm.o wrrle.o wrtarga.o -o djpeg.js --embed-file testimgp.jpg --embed-file testimg.jpg

# works (trows a error at the end but the generated byte code at the top is correct)
node djpeg.js -bmp testimg.jpg

# fails :(
node djpeg.js -bmp testimgp.jpg
kripken commented 12 years ago

Thanks for the easy testcase. I can reproduce this. Looks like the issue is a function pointer is not converted to an integer ID properly. Not sure yet why.

kripken commented 12 years ago

Ok, this should now be fixed on emscripten's incoming branch. This file seems to run ok now.

bompo commented 12 years ago

Thanks!! Works for me! Is there a way to keep the FS object in -O2 mode? Seems like closure or the optimizer removes the file system object... :/

kripken commented 12 years ago

Closure minifies it when it optimizes, the trick is to write FS-using code in --pre-js so it gets optimized together with the rest of the code. See emcc --help and examples using FS stuff in tests/runner.py