Skip to content

Commit

Permalink
Store memory initialization in string literal if requested
Browse files Browse the repository at this point in the history
With “--memory-init-file 0 -s MEM_INIT_METHOD=2” on the command line, the
generated JavaScript file will contain a string literal representing the
initial content of the memory buffer.

The MEM_INIT_METHOD defaults to 0 but gets set to 1 if --memory-init-file is
being used.  Setting it to 1 without --memory-init-file will cause an error.
That way, we can use the setting in the postamble, without too many changes
in other places.

Since memory is initialized to all zero, trailing zeros can be omitted.
This change affects the file-based initialization as well.
  • Loading branch information
gagern committed Jun 15, 2015
1 parent 92094e4 commit 8f44c9f
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 10 deletions.
20 changes: 18 additions & 2 deletions emcc
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,10 @@ try:
# Emscripten
logging.debug('LLVM => JS')
extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))]
if memory_init_file:
shared.Settings.MEM_INIT_METHOD = 1
elif shared.Settings.MEM_INIT_METHOD == 1:
shared.Settings.MEM_INIT_METHOD = 0
final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
if DEBUG: save_intermediate('original')

Expand Down Expand Up @@ -1340,14 +1344,26 @@ try:

js_transform_tempfiles = [final]

if memory_init_file:
if memory_init_file or shared.Settings.MEM_INIT_METHOD == 2:
memfile = target + '.mem'
shared.try_delete(memfile)
def repl(m):
# handle chunking of the memory initializer
s = m.groups(0)[0]
if len(s) == 0 and not shared.Settings.EMTERPRETIFY: return m.group(0) # emterpreter must have a mem init file; otherwise, don't emit 0-size ones
open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(','))))
membytes = [int(x or '0') for x in s.split(',')]
if not shared.Settings.EMTERPRETIFY:
while membytes and membytes[-1] == 0:
membytes.pop()
if not membytes:
return '';
membytes = ''.join(map(chr, membytes))
if not memory_init_file:
s = repr(membytes)
hex_to_octal = lambda x: '\\%o' % int(x.group(1), 16)
s = re.sub(r'\\x([0-1][0-9A-Fa-f])(?:(?=[^0-9])|$)', hex_to_octal, s)
return 'var memoryInitializer = %s;' % s
open(memfile, 'wb').write(membytes)
if DEBUG:
# Copy into temp dir as well, so can be run there too
shared.safe_copy(memfile, os.path.join(shared.get_emscripten_temp_dir(), os.path.basename(memfile)))
Expand Down
12 changes: 12 additions & 0 deletions src/postamble.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@

// === Auto-generated postamble setup entry stuff ===

#if MEM_INIT_METHOD == 2
#if USE_PTHREADS
if (memoryInitializer && !ENVIRONMENT_IS_PTHREAD) (function(s) {
#else
if (memoryInitializer) (function(s) {
#endif
for (var i = 0; i < s.length; ++i) HEAPU8[STATIC_BASE + i] = s.charCodeAt(i);
})(memoryInitializer);
#else
#if MEM_INIT_METHOD == 1
#if USE_PTHREADS
if (memoryInitializer && !ENVIRONMENT_IS_PTHREAD) {
#else
Expand Down Expand Up @@ -52,6 +62,8 @@ if (memoryInitializer) {
}
}
}
#endif
#endif

function ExitStatus(status) {
this.name = "ExitStatus";
Expand Down
5 changes: 5 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ var INVOKE_RUN = 1; // Whether we will run the main() function. Disable if you e
// can do with Module.callMain(), with an optional parameter of commandline args).
var NO_EXIT_RUNTIME = 0; // If set, the runtime is not quit when main() completes (allowing code to
// run afterwards, for example from the browser main event loop).
var MEM_INIT_METHOD = 0; // How to represent the initial memory content.
// 0: keep array literal representing the initial memory data
// 1: create a *.mem file containing the binary data of the initial memory;
// use the --memory-init-file command line switch to select this method
// 2: embed a string literal representing that initial memory data
var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlarge the stack, so this
// value must be large enough for the program's requirements. If
// assertions are on, we will assert on not exceeding this, otherwise,
Expand Down
16 changes: 9 additions & 7 deletions tests/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ def skipme(self): # used by tests we ask on the commandline to be skipped, see r
def is_emterpreter(self):
return False

def uses_memory_init_file(self):
if self.emcc_args is None:
return None
elif '--memory-init-file' in self.emcc_args:
return int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1])
else:
return ('-O2' in self.emcc_args or '-O3' in self.emcc_args or '-Oz' in self.emcc_args) and not Settings.SIDE_MODULE

def setUp(self):
Settings.reset()
self.banned_js_engines = []
Expand Down Expand Up @@ -252,16 +260,10 @@ def build(self, src, dirname, filename, output_processor=None, main_file=None, a
output_processor(open(filename + '.o.js').read())

if self.emcc_args is not None:
if '--memory-init-file' in self.emcc_args:
memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1])
else:
memory_init_file = ('-O2' in self.emcc_args or '-O3' in self.emcc_args or '-Oz' in self.emcc_args) and not Settings.SIDE_MODULE
src = open(filename + '.o.js').read()
if memory_init_file:
if self.uses_memory_init_file():
# side memory init file, or an empty one in the js
assert ('/* memory initializer */' not in src) or ('/* memory initializer */ allocate([]' in src)
else:
assert 'memory initializer */' in src or '/*' not in src # memory initializer comment, or cleaned-up source with no comments

def validate_asmjs(self, err):
if 'uccessfully compiled asm.js code' in err and 'asm.js link error' not in err:
Expand Down
3 changes: 2 additions & 1 deletion tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4549,7 +4549,7 @@ def process(filename):
try_delete(mem_file)
self.do_run(src, ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n5 bytes to dev/null: 5\nok.\n \ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n5 bytes to dev/null: 5\nok.\n'),
post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
if '-O2' in self.emcc_args:
if self.uses_memory_init_file():
assert os.path.exists(mem_file)

def test_files_m(self):
Expand Down Expand Up @@ -7387,6 +7387,7 @@ def setUp(self):
asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "-s", "SAFE_HEAP=1"])
asm1i = make_run("asm1i", compiler=CLANG, emcc_args=["-O1", '-s', 'EMTERPRETIFY=1'])
asm3i = make_run("asm3i", compiler=CLANG, emcc_args=["-O3", '-s', 'EMTERPRETIFY=1'])
asm2m = make_run("asm2m", compiler=CLANG, emcc_args=["-O2", "--memory-init-file", "0", "-s", "MEM_INIT_METHOD=2"])

# Legacy test modes -
asm2nn = make_run("asm2nn", compiler=CLANG, emcc_args=["-O2"], env={"EMCC_NATIVE_OPTIMIZER": "0"})
Expand Down

0 comments on commit 8f44c9f

Please sign in to comment.