Skip to content

Commit

Permalink
replace --memory-init-file 0 logic with SINGLE_FILE-style embedding (e…
Browse files Browse the repository at this point in the history
  • Loading branch information
buu700 committed Jun 13, 2017
1 parent 3a562fa commit 7169a30
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 113 deletions.
20 changes: 5 additions & 15 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1605,7 +1605,9 @@ def get_final():

with ToolchainProfiler.profile_block('memory initializer'):
memfile = None
if shared.Settings.MEM_INIT_METHOD > 0:
embed_memfile = shared.Settings.MEM_INIT_METHOD == 0 and (not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE and options.debug_level < 4)

if shared.Settings.MEM_INIT_METHOD > 0 or embed_memfile:
memfile = target + '.mem'
shared.try_delete(memfile)
def repl(m):
Expand All @@ -1616,20 +1618,17 @@ def repl(m):
while membytes and membytes[-1] == 0:
membytes.pop()
if not membytes: return ''
if not options.memory_init_file:
# memory initializer in a string literal
return "memoryInitializer = '%s';" % shared.JS.generate_string_initializer(list(membytes))
open(memfile, 'wb').write(''.join(map(chr, 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)))
if not shared.Settings.BINARYEN:
return 'memoryInitializer = "%s";' % shared.JS.get_subresource_location(memfile)
return 'memoryInitializer = "%s";' % shared.JS.get_subresource_location(memfile, embed_memfile)
else:
# with wasm, we may have the mem init file in the wasm binary already
return ('memoryInitializer = Module["wasmJSMethod"].indexOf("asmjs") >= 0 || '
'Module["wasmJSMethod"].indexOf("interpret-asm2wasm") >= 0 ? "%s" : null;'
% shared.JS.get_subresource_location(memfile))
% shared.JS.get_subresource_location(memfile, embed_memfile))
src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1)
open(final + '.mem.js', 'w').write(src)
final += '.mem.js'
Expand All @@ -1641,15 +1640,6 @@ def repl(m):
logging.debug('wrote memory initialization to %s', memfile)
else:
logging.debug('did not see memory initialization')
elif not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE and options.debug_level < 4:
# not writing a binary init, but we can at least optimize them by splitting them up
src = open(final).read()
src = shared.JS.optimize_initializer(src)
if src is not None:
logging.debug('optimizing memory initialization')
open(final + '.mem.js', 'w').write(src)
final += '.mem.js'
src = None

if shared.Settings.USE_PTHREADS:
target_dir = os.path.dirname(os.path.abspath(target))
Expand Down
2 changes: 0 additions & 2 deletions src/postamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ if (memoryInitializer) (function(s) {
}
})(memoryInitializer);
#else
#if MEM_INIT_METHOD == 1
#if USE_PTHREADS
if (memoryInitializer && !ENVIRONMENT_IS_PTHREAD) {
#else
Expand Down Expand Up @@ -94,7 +93,6 @@ if (memoryInitializer) {
}
}
#endif
#endif

#if CYBERDWARF
Module['cyberdwarf'] = _cyberdwarf_Debugger(cyberDWARFFile);
Expand Down
98 changes: 2 additions & 96 deletions tools/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -2279,8 +2279,8 @@ def to_nice_ident(ident): # limited version of the JS function toNiceIdent

# Returns the subresource location for run-time access
@staticmethod
def get_subresource_location(path):
if Settings.SINGLE_FILE:
def get_subresource_location(path, force_data_uri=False):
if Settings.SINGLE_FILE or force_data_uri:
f = open(path, 'rb')
data = base64.b64encode(f.read())
f.close()
Expand Down Expand Up @@ -2400,100 +2400,6 @@ def align(x, by):
while x % by != 0: x += 1
return x

INITIALIZER_CHUNK_SIZE = 10240

@staticmethod
def collect_initializers(src):
ret = []
max_offset = -1
for init in re.finditer(JS.memory_initializer_pattern, src):
contents = init.group(1).split(',')
offset = sum([int(x) if x[0] != 'R' else 0 for x in init.group(2).split('+')])
ret.append((offset, contents))
assert offset > max_offset
max_offset = offset
return ret

@staticmethod
def split_initializer(contents):
# given a memory initializer (see memory_initializer_pattern), split it up into multiple initializers to avoid long runs of zeros or a single overly-large allocator
ret = []
l = len(contents)
maxx = JS.INITIALIZER_CHUNK_SIZE
i = 0
start = 0
while 1:
if i - start >= maxx or (i > start and i == l):
#print >> sys.stderr, 'new', start, i-start
ret.append((start, contents[start:i]))
start = i
if i == l: break
if contents[i] != '0':
i += 1
else:
# look for a sequence of zeros
j = i + 1
while j < l and contents[j] == '0': j += 1
if j-i > maxx/10 or j-start >= maxx:
#print >> sys.stderr, 'skip', start, i-start, j-start
ret.append((start, contents[start:i])) # skip over the zeros starting at i and ending at j
start = j
i = j
return ret

@staticmethod
def replace_initializers(src, inits):
class State:
first = True
def rep(m):
if not State.first: return ''
# write out all the new initializers in place of the first old one
State.first = False
def gen_init(init):
offset, contents = init
return '/* memory initializer */ allocate([%s], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE%s);' % (
','.join(contents),
'' if offset == 0 else ('+%d' % offset)
)
return '\n'.join(map(gen_init, inits))
return re.sub(JS.memory_initializer_pattern, rep, src)

@staticmethod
def optimize_initializer(src):
inits = JS.collect_initializers(src)
if len(inits) == 0: return None
assert len(inits) == 1
init = inits[0]
offset, contents = init
assert offset == 0 # offset 0, singleton
if len(contents) <= JS.INITIALIZER_CHUNK_SIZE: return None
return JS.replace_initializers(src, JS.split_initializer(contents))

@staticmethod
def generate_string_initializer(s):
if Settings.ASSERTIONS:
# append checksum of length and content
crcTable = []
for i in range(256):
crc = i
for bit in range(8):
crc = (crc >> 1) ^ ((crc & 1) * 0xedb88320)
crcTable.append(crc)
crc = 0xffffffff
n = len(s)
crc = crcTable[(crc ^ n) & 0xff] ^ (crc >> 8)
crc = crcTable[(crc ^ (n >> 8)) & 0xff] ^ (crc >> 8)
for i in s:
crc = crcTable[(crc ^ i) & 0xff] ^ (crc >> 8)
for i in range(4):
s.append((crc >> (8 * i)) & 0xff)
s = ''.join(map(chr, s))
s = s.replace('\\', '\\\\').replace("'", "\\'")
s = s.replace('\n', '\\n').replace('\r', '\\r')
# Escape the ^Z (= 0x1a = substitute) ASCII character and all characters higher than 7-bit ASCII.
def escape(x): return '\\x{:02x}'.format(ord(x.group()))
return re.sub('[\x1a\x80-\xff]', escape, s)

@staticmethod
def is_dyn_call(func):
return func.startswith('dynCall_')
Expand Down

0 comments on commit 7169a30

Please sign in to comment.