aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-06-05 19:17:53 -0700
committerAlon Zakai <alonzakai@gmail.com>2011-06-05 19:17:53 -0700
commite068f02137c1de07480886c0f6181150d77816dd (patch)
treeffc61c76fe4c0bf9fd58e6c7105c3c4378501698
parent5b2f181ab4662dca21f3605aeca8c2e0cd212b20 (diff)
fix alignment issues with USE_TYPED_ARRAYS == 2
-rw-r--r--src/analyzer.js1
-rw-r--r--src/parseTools.js15
-rw-r--r--src/preamble.js66
-rw-r--r--src/runtime.js19
-rw-r--r--src/settings.js9
-rw-r--r--tests/runner.py7
6 files changed, 94 insertions, 23 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index caeedb56..ca021e45 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -534,6 +534,7 @@ function analyzer(data) {
for (var i = 0; i < lines.length; i++) {
var item = lines[i].value;
if (!item || item.intertype != 'alloca') break;
+ if (USE_TYPED_ARRAYS === 2) index = Runtime.forceAlign(index, Math.min(item.allocatedSize, QUANTUM_SIZE));
item.allocatedIndex = index;
index += item.allocatedSize;
delete item.allocatedSize;
diff --git a/src/parseTools.js b/src/parseTools.js
index 5813c908..fab3eccd 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -665,8 +665,7 @@ function getHeapOffset(offset, type) {
return offset;
} else {
if (getNativeFieldSize(type) > 4) {
- dprint(type + ' has size > 4, which means we cannot be guaranteed to load it aligned! For now, USE_TYPED_ARRAYS==2 cannot handle that.');
- return 'abort("size > 4, alignment issues with USE_TYPED_ARRAYS==2")';
+ type = 'i32'; // XXX we emulate 64-bit values as 32
}
return '((' + offset + ')>>' + (Math.log(getNativeFieldSize(type, true))/Math.LN2) + ')';
}
@@ -876,13 +875,21 @@ function makeGetSlabs(ptr, type, allowMultiple) {
}
} else { // USE_TYPED_ARRAYS == 2)
if (isPointerType(type)) type = 'i32'; // Hardcoded 32-bit
+ function warn64() {
+ if (!Debugging.shownUTA2_64Warning) {
+ dprint('WARNING: .ll contains i64 or double values. These 64-bit values are dangerous in USE_TYPED_ARRAYS == 2.');
+ dprint(' We store i64 as i32, and double as float. This can cause serious problems!');
+ Debugging.shownUTA2_64Warning = true;
+ }
+ }
switch(type) {
+ case 'i1': return ['HEAP8']; break;
case 'i8': return ['HEAP8']; break;
case 'i16': return ['HEAP16']; break;
case 'i32': return ['HEAP32']; break;
- case 'i64': return ['abort("No HEAP64")']; break;
case 'float': return ['HEAPF32']; break;
- case 'double': return ['HEAPF64']; break;
+ case 'i64': warn64(); return ['HEAP32']; break;
+ case 'double': warn64(); return ['HEAPF32']; break;
default: {
throw 'what, exactly, can we do for unknown types in TA2?! ' + new Error().stack;
}
diff --git a/src/preamble.js b/src/preamble.js
index dd7f9f3e..e0f97f48 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -52,6 +52,10 @@ function SAFE_HEAP_ACCESS(dest, type, store, ignore) {
}
}
function SAFE_HEAP_STORE(dest, value, type, ignore) {
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP store: ' + [dest, type, value, ignore]);
+#endif
+
if (!ignore && !value && value !== 0 && value !== false) { // false can be the result of a mathop comparator
throw('Warning: Writing an invalid value of ' + JSON.stringify(value) + ' at ' + dest + ' :: ' + new Error().stack + '\n');
}
@@ -75,11 +79,11 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) {
if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
switch(type) {
case 'i8': HEAP8[dest] = value; break;
- case 'i16': HEAP16[dest>>1] = value; break;
- case 'i32': HEAP32[dest>>2] = value; break;
- case 'i64': abort('no HEAP64'); break;
- case 'float': HEAPF32[dest>>2] = value; break;
- case 'double': HEAPF64[dest>>3] = value; break;
+ case 'i16': assert(dest % 2 === 0, type + ' loads must be aligned'); HEAP16[dest>>1] = value; break;
+ case 'i32': assert(dest % 4 === 0, type + ' loads must be aligned'); HEAP32[dest>>2] = value; break;
+ case 'i64': assert(dest % 4 === 0, type + ' loads must be aligned'); HEAP32[dest>>2] = value; break; // XXX store int64 as int32
+ case 'float': assert(dest % 4 === 0, type + ' loads must be aligned'); HEAPF32[dest>>2] = value; break;
+ case 'double': assert(dest % 4 === 0, type + ' loads must be aligned'); HEAPF32[dest>>2] = value; break; // XXX store doubles as floats
default: throw 'weird type for typed array II: ' + type + new Error().stack;
}
#else
@@ -92,24 +96,61 @@ function SAFE_HEAP_LOAD(dest, type, ignore) {
#if USE_TYPED_ARRAYS == 1
if (type in Runtime.FLOAT_TYPES) {
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, type, FHEAP[dest], ignore]);
+#endif
return FHEAP[dest];
} else {
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, type, IHEAP[dest], ignore]);
+#endif
return IHEAP[dest];
}
#else
#if USE_TYPED_ARRAYS == 2
+#if SAFE_HEAP_LOG
+ var originalType = type;
+#endif
if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
switch(type) {
- case 'i8': return HEAP8[dest]; break;
- case 'i16': return HEAP16[dest>>1]; break;
- case 'i32': return HEAP32[dest>>2]; break;
- case 'i64': abort('no HEAP64'); break;
- case 'float': return HEAPF32[dest>>2]; break;
- case 'double': return HEAPF64[dest>>3]; break;
+ case 'i8': {
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, originalType, HEAP8[dest], ignore]);
+#endif
+ return HEAP8[dest];
+ break;
+ }
+ case 'i16': {
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, originalType, HEAP16[dest], ignore]);
+#endif
+ assert(dest % 2 === 0, type + ' loads must be aligned');
+ return HEAP16[dest>>1];
+ break;
+ }
+ case 'i32': case 'i64': { // XXX store int64 as int32
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, originalType, HEAP32[dest], ignore]);
+#endif
+ assert(dest % 4 === 0, type + ' loads must be aligned');
+ return HEAP32[dest>>2];
+ break;
+ }
+ case 'float': case 'double': { // XXX store doubles as floats
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, originalType, HEAPF32[dest], ignore]);
+#endif
+ assert(dest % 4 === 0, type + ' loads must be aligned');
+ return HEAPF32[dest>>2];
+ break;
+ }
default: throw 'weird type for typed array II: ' + type;
}
return null;
#else
+#if SAFE_HEAP_LOG
+ print('SAFE_HEAP load: ' + [dest, type, HEAP[dest], ignore]);
+#endif
return HEAP[dest];
#endif
#endif
@@ -350,7 +391,7 @@ var HEAP;
var IHEAP, FHEAP;
#endif
#if USE_TYPED_ARRAYS == 2
-var HEAP8, HEAP16, HEAP32, HEAPF32, HEAPF64;
+var HEAP8, HEAP16, HEAP32, HEAPF32;
#endif
var STACK_ROOT, STACKTOP, STACK_MAX;
@@ -377,7 +418,6 @@ function __initializeRuntime__() {
HEAP16 = new Int16Array(buffer);
HEAP32 = new Int32Array(buffer);
HEAPF32 = new Float32Array(buffer);
- HEAPF64 = new Float64Array(buffer);
#endif
} else
#endif
diff --git a/src/runtime.js b/src/runtime.js
index adf62521..4246ad1c 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -22,6 +22,7 @@ RuntimeGenerator = {
// An allocation that lives as long as the current function call
stackAlloc: function(size) {
+ if (USE_TYPED_ARRAYS === 2) 'STACKTOP += STACKTOP % ' + (QUANTUM_SIZE - (isNumber(size) ? Math.min(size, QUANTUM_SIZE) : QUANTUM_SIZE)) + ';';
var ret = RuntimeGenerator.alloc(size, 'STACK', INIT_STACK);
if (ASSERTIONS) {
ret += '; assert(STACKTOP < STACK_ROOT + STACK_MAX, "Ran out of stack")';
@@ -31,6 +32,7 @@ RuntimeGenerator = {
stackEnter: function(initial) {
if (initial === 0 && SKIP_STACK_IN_SMALL) return '';
+ if (USE_TYPED_ARRAYS === 2) initial = Runtime.forceAlign(initial);
var ret = 'var __stackBase__ = STACKTOP; STACKTOP += ' + initial;
if (ASSERTIONS) {
ret += '; assert(STACKTOP < STACK_MAX)';
@@ -59,7 +61,7 @@ RuntimeGenerator = {
if (typeof quantum !== 'number') {
quantum = '(quantum ? quantum : QUANTUM_SIZE)';
}
- return target + ' = Math.ceil(' + target + '/' + quantum + ')*' + quantum + ';';
+ return target + ' = ' + Runtime.forceAlign(target, quantum) + ';';
}
};
@@ -70,9 +72,14 @@ function unInline(name_, params) {
}
Runtime = {
- stackAlloc: unInline('stackAlloc', ['size']),
- staticAlloc: unInline('staticAlloc', ['size']),
- alignMemory: unInline('alignMemory', ['size', 'quantum']),
+ forceAlign: function(target, quantum) {
+ quantum = quantum || QUANTUM_SIZE;
+ if (isNumber(target) && isNumber(quantum)) {
+ return Math.ceil(target/quantum)*quantum;
+ } else {
+ return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+ }
+ },
isNumberType: function(type) {
return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
@@ -167,6 +174,10 @@ Runtime = {
}
};
+Runtime.stackAlloc = unInline('stackAlloc', ['size']);
+Runtime.staticAlloc = unInline('staticAlloc', ['size']);
+Runtime.alignMemory = unInline('alignMemory', ['size', 'quantum']);
+
function getRuntime() {
var ret = 'var Runtime = {\n';
for (i in Runtime) {
diff --git a/src/settings.js b/src/settings.js
index cbdb6ac1..f2dd9065 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -39,6 +39,13 @@ INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to
OPTIMIZE = 0; // Optimize llvm operations into js commands
RELOOP = 0; // Recreate js native loops from llvm data
USE_TYPED_ARRAYS = 0; // Try to use typed arrays for the heap
+ // 1 has two heaps, IHEAP (int32) and FHEAP (double),
+ // and addresses there are a match for normal addresses. This wastes memory but can be fast.
+ // 2 is a single heap, accessible through views as int8, int32, etc. This saves memory but
+ // has more overhead of pointer calculations. It also is limited to storing doubles as floats,
+ // simply because double stores are not necessarily 64-bit aligned, and we can only access
+ // 64-bit aligned values with a 64-bit typed array. Likewise int64s are stored as int32's,
+ // which is potentially very dangerous!
SKIP_STACK_IN_SMALL = 1; // When enabled, does not push/pop the stack at all in
// functions that have no basic stack usage. But, they
// may allocate stack later, and in a loop, this can be
@@ -51,6 +58,8 @@ SAFE_HEAP = 0; // Check each write to the heap against a list of blocked address
// SAFE_HEAP_LINES, checking only the specified lines.
// If equal to 3, checking all *but* the specified lines. Note
// that 3 is the option you usually want here.
+SAFE_HEAP_LOG = 0; // Log out all SAFE_HEAP operations
+
LABEL_DEBUG = 0; // Print out labels and functions as we enter them
EXCEPTION_DEBUG = 1; // Print out exceptions in emscriptened code
EXECUTION_TIMEOUT = -1; // Throw an exception after X seconds - useful to debug infinite loops
diff --git a/tests/runner.py b/tests/runner.py
index 489196e3..738f639e 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -302,6 +302,8 @@ if 'benchmark' not in sys.argv:
# Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
if js_engines is None:
js_engines = [SPIDERMONKEY_ENGINE, V8_ENGINE]
+ if USE_TYPED_ARRAYS == 2:
+ js_engines = [SPIDERMONKEY_ENGINE] # when oh when will v8 support typed arrays in the console
for engine in js_engines:
js_output = self.run_generated_code(engine, filename + '.o.js', args)
if output_nicerizer is not None:
@@ -2514,8 +2516,9 @@ TT = %s
for llvm_opts in [0,1]:
for name, compiler, quantum, embetter, typed_arrays in [
('clang', CLANG, 1, 0, 0), ('clang', CLANG, 4, 0, 0), ('llvm_gcc', LLVM_GCC, 4, 0, 0),
- ('clang', CLANG, 1, 1, 1), ('clang', CLANG, 4, 1, 1), ('llvm_gcc', LLVM_GCC, 4, 1, 1)#,
-# ('clang', CLANG, 4, 1, 2), ('llvm_gcc', LLVM_GCC, 4, 1, 2)
+ ('clang', CLANG, 1, 1, 1), ('clang', CLANG, 4, 1, 1), ('llvm_gcc', LLVM_GCC, 4, 1, 1),
+# ('clang', CLANG, 4, 1, 2),
+# ('llvm_gcc', LLVM_GCC, 4, 0, 2)
]:
fullname = '%s_%d_%d%s%s' % (
name, llvm_opts, embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays)