-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory initializer in string literal #3326
Changes from all commits
8f44c9f
c388aee
6d3b9ff
e2d59af
f5bc422
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
else: | ||
assert shared.Settings.MEM_INIT_METHOD != 1 | ||
final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args) | ||
if DEBUG: save_intermediate('original') | ||
|
||
|
@@ -1340,18 +1344,47 @@ try: | |
|
||
js_transform_tempfiles = [final] | ||
|
||
if memory_init_file: | ||
if shared.Settings.MEM_INIT_METHOD > 0: | ||
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(',')))) | ||
s = m.group(1) | ||
if len(s) == 0: return '' # don't emit 0-size ones | ||
membytes = [int(x or '0') for x in s.split(',')] | ||
while membytes and membytes[-1] == 0: | ||
membytes.pop() | ||
if not membytes: return '' | ||
if not memory_init_file: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this section needs a comment |
||
# memory initializer in a string literal | ||
s = list(membytes) | ||
if shared.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') | ||
def escape(x): return '\\x{:02x}'.format(ord(x.group())) | ||
s = re.sub('[\x80-\xff]', escape, s) | ||
return "memoryInitializer = '%s';" % s | ||
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))) | ||
return 'var memoryInitializer = "%s";' % os.path.basename(memfile) | ||
return 'memoryInitializer = "%s";' % os.path.basename(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' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,35 @@ | ||
|
||
// === 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 | ||
var i, n = s.length; | ||
#if ASSERTIONS | ||
n -= 4; | ||
var crc, bit, table = new Int32Array(256); | ||
for (i = 0; i < 256; ++i) { | ||
for (crc = i, bit = 0; bit < 8; ++bit) | ||
crc = (crc >>> 1) ^ ((crc & 1) * 0xedb88320); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. curly braces |
||
table[i] = crc >>> 0; | ||
} | ||
crc = -1; | ||
crc = table[(crc ^ n) & 0xff] ^ (crc >>> 8); | ||
crc = table[(crc ^ (n >>> 8)) & 0xff] ^ (crc >>> 8); | ||
for (i = 0; i < s.length; ++i) { | ||
crc = table[(crc ^ s.charCodeAt(i)) & 0xff] ^ (crc >>> 8); | ||
} | ||
assert(crc === 0, "memory initializer checksum"); | ||
#endif | ||
for (i = 0; i < n; ++i) { | ||
HEAPU8[STATIC_BASE + i] = s.charCodeAt(i); | ||
} | ||
})(memoryInitializer); | ||
#else | ||
#if MEM_INIT_METHOD == 1 | ||
#if USE_PTHREADS | ||
if (memoryInitializer && !ENVIRONMENT_IS_PTHREAD) { | ||
#else | ||
|
@@ -52,6 +81,8 @@ if (memoryInitializer) { | |
} | ||
} | ||
} | ||
#endif | ||
#endif | ||
|
||
function ExitStatus(status) { | ||
this.name = "ExitStatus"; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
unsigned char problematic[] = { 0x20, 0x7c, 0x02, 0x07, 0x5f, 0xa0, 0xdf }; | ||
int main() { | ||
unsigned char a, b; | ||
int result = 0, i, j; | ||
for (i = 0; i < sizeof(problematic); ++i) { | ||
a = problematic[i] ^ 32; | ||
for (j = 0; j < sizeof(problematic); ++j) { | ||
b = problematic[j] ^ 32; | ||
if (((const unsigned char)data[a][2*b]) != a || | ||
((const unsigned char)data[a][2*b + 1]) != b) { | ||
result = 1; | ||
printf("data[0x%02x][0x%03x]=%x02x\n", a, 2*b, data[a][2*b]); | ||
printf("data[0x%02x][0x%03x]=%x02x\n", a, 2*b + 1, data[a][2*b + 1]); | ||
} | ||
} | ||
} | ||
REPORT_RESULT() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,7 +38,7 @@ def path_from_root(*pathelems): | |
|
||
# Core test runner class, shared between normal tests and benchmarks | ||
checked_sanity = False | ||
test_modes = ['default', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm1i', 'asm3i', 'asm2nn'] | ||
test_modes = ['default', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm1i', 'asm3i', 'asm2m', 'asm2nn'] | ||
test_index = 0 | ||
|
||
use_all_engines = os.environ.get('EM_ALL_ENGINES') # generally js engines are equivalent, testing 1 is enough. set this | ||
|
@@ -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 = [] | ||
|
@@ -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(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kripken: Judging from your lack of comment on this line, I take it that dropping this particular check is OK? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes. |
||
# 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: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a new optimization?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, stripping trailing zeros is new. At least in this context; don't know whether the
split_initializer
code affects trailing zeros as well.