aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-10-16 18:40:27 -0700
committerAlon Zakai <alonzakai@gmail.com>2012-10-17 12:44:21 -0700
commitee500a3d942327563451bfc81dee0a3044a3cb7e (patch)
treed5674ccc751f4e004b15b025929a88e6e6e005d7
parenta2b4acbd95c1f307d0d51bfd0134f6a88a087c46 (diff)
UNALIGNED_MEMORY option to emulate unaligned reads/writes all the time, to support some nonportable code
-rw-r--r--src/parseTools.js8
-rw-r--r--src/settings.js4
-rwxr-xr-xtests/runner.py25
3 files changed, 29 insertions, 8 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 80ba269b..8e919d15 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -905,6 +905,7 @@ function getHeapOffset(offset, type) {
// See makeSetValue
function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) {
+ if (UNALIGNED_MEMORY) align = 1;
if (isStructType(type)) {
var typeData = Types.types[type];
var ret = [];
@@ -930,7 +931,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
// Special case that we can optimize
ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore) + '+' +
'(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore) + '<<16)';
- } else if (bytes <= 4) {
+ } else { // XXX we cannot truly handle > 4...
ret = '';
for (var i = 0; i < bytes; i++) {
ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore) + (i > 0 ? '<<' + (8*i) : '') + ')';
@@ -983,7 +984,8 @@ function indexizeFunctions(value, type) {
//! 'null' means, in the context of SAFE_HEAP, that we should accept all types;
//! which means we should write to all slabs, ignore type differences if any on reads, etc.
//! @param noNeedFirst Whether to ignore the offset in the pointer itself.
-function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep) {
+function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) {
+ if (UNALIGNED_MEMORY && !forcedAlign) align = 1;
sep = sep || ';';
if (isStructType(type)) {
var typeData = Types.types[type];
@@ -1026,7 +1028,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
}
}
} else {
- ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8) + sep;
+ ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, null, null, true) + sep;
ret += makeCopyValues(getFastValue(ptr, '+', pos), 'tempDoublePtr', Runtime.getNativeTypeSize(type), type, null, align, sep);
}
return ret;
diff --git a/src/settings.js b/src/settings.js
index 0b58a26f..5b1968b9 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -72,6 +72,10 @@ var DOUBLE_MODE = 1; // How to load and store 64-bit doubles. Without typed arra
// then load it aligned, and that load-store will make JS engines alter it if it is being
// stored to a typed array for security reasons. That will 'fix' the number from being a
// NaN or an infinite number.
+var UNALIGNED_MEMORY = 0; // If enabled, all memory accesses are assumed to be unaligned. (This only matters in
+ // typed arrays mode 2 where alignment is relevant.) In unaligned memory mode, you
+ // can run nonportable code that typically would break in JS (or on ARM for that
+ // matter, which also cannot do unaligned reads/writes), at the cost of slowness
var PRECISE_I64_MATH = 1; // If enabled, i64 addition etc. is emulated - which is slow but precise. If disabled,
// we use the 'double trick' which is fast but incurs rounding at high values.
// Note that we do not catch 32-bit multiplication by default (which must be done in
diff --git a/tests/runner.py b/tests/runner.py
index de8acaef..db566c3f 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -1183,16 +1183,11 @@ c5,de,15,8a
}
'''
- Settings.EMULATE_UNALIGNED_ACCESSES = 0
-
try:
self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n')
except Exception, e:
assert 'must be aligned' in str(e), e # expected to fail without emulation
- # XXX TODO Settings.EMULATE_UNALIGNED_ACCESSES = 1
- #self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n') # but succeeds with it
-
def test_unsigned(self):
Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here
Settings.CHECK_SIGNS = 0
@@ -7279,6 +7274,26 @@ f.close()
Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-fcatch-undefined-behavior']).communicate()
self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ def test_unaligned_memory(self):
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ typedef unsigned char Bit8u;
+ typedef unsigned short Bit16u;
+ typedef unsigned int Bit32u;
+
+ int main()
+ {
+ Bit8u data[4] = {0x01,0x23,0x45,0x67};
+
+ printf("data: %x\n", *(Bit32u*)data);
+ printf("data[0,1] 16bit: %x\n", *(Bit16u*)data);
+ printf("data[1,2] 16bit: %x\n", *(Bit16u*)(data+1));
+ }
+ ''')
+ 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_l_link(self):
# Linking with -lLIBNAME and -L/DIRNAME should work