aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoralon@honor <none@none>2010-09-25 20:26:16 -0700
committeralon@honor <none@none>2010-09-25 20:26:16 -0700
commitb94c061e122f155cc5c1262a1bb470cb49ee04b4 (patch)
tree134322b7ed16b9a3ed805d4663e3233625d5ef7a /src
parent481dec302bfb02b574741c4e505d274718854dff (diff)
optional memory alignment that matches c/c++; used in clang, not in llvm-gcc
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js10
-rw-r--r--src/jsifier.js52
-rw-r--r--src/parseTools.js32
-rw-r--r--src/postamble.js7
-rw-r--r--src/preamble.js16
-rw-r--r--src/settings.js15
-rw-r--r--src/utility.js6
7 files changed, 118 insertions, 20 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 93e61f1c..13c5c648 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -92,7 +92,7 @@ function analyzer(data) {
if (isNumberType(type) || isPointerType(type)) return;
data.types[type] = {
name_: type,
- fields: [ 'int32' ], // XXX
+ fields: [ 'i32' ], // XXX
flatSize: 1,
lineNum: '?',
};
@@ -166,9 +166,13 @@ function analyzer(data) {
var sizes = [];
type.flatIndexes = type.fields.map(function(field) {
var soFar = type.flatSize;
- var size = 1;
- if (isStructType(field)) {
+ var size;
+ if (isNumberType(field) || isPointerType(field)) {
+ size = getNativeFieldSize(field);
+ } else if (isStructType(field)) {
size = item.types[field].flatSize;
+ } else {
+ assert(0);
}
type.flatSize += size;
sizes.push(size);
diff --git a/src/jsifier.js b/src/jsifier.js
index 305f4a8f..381b4cf7 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -66,6 +66,33 @@ function JSify(data) {
return ret;
}
+ function alignStruct(values, type) {
+ dprint('types', 'alignStruct: ' + dump(type));
+ // XXX hardcoded ptr impl
+ var ret = [];
+ var typeData = TYPES[type];
+ assertTrue(typeData);
+ var i = 0;
+ while (i < values.length) {
+ var currField = typeData.fields[i];
+ var currValue = values[i];
+ if (isStructType[currField]) {
+ var fieldTypeData = TYPES[currField];
+ assertTrue(fieldTypeData);
+ ret = ret.concat(alignStruct(values.slice(i, fieldTypeData.fields.length), currField));
+ i += fieldTypeData.fields.length;
+ } else {
+ ret.push(currValue);
+ // pad to align, unless it's a structure and already aligned
+ if (currValue[0] != '[') {
+ ret = ret.concat(zeros(getNativeFieldSize(currField)-1));
+ }
+ i += 1;
+ }
+ }
+ return ret;
+ }
+
// Gets an entire constant expression
function parseConst(value, type) {
dprint('gconst', '//yyyyy ' + JSON.stringify(value) + ',' + type + '\n');
@@ -95,25 +122,27 @@ function JSify(data) {
var subSegments = splitTokenList(segment[2].item[0].tokens);
return '(' + handleSegment(subSegments[0]) + ' + ' + handleSegment(subSegments[1]) + ')';
} else if (segment[1].type == '{') {
- return '[' + handleSegments(segment[1].tokens) + ']';
+ // struct
+ var type = segment[0].text;
+ return '[' + alignStruct(handleSegments(segment[1].tokens), type).join(', ') + ']';
} else if (segment[1].type == '[') {
- return '[' + handleSegments(segment[1].item[0].tokens) + ']';
+ return '[' + handleSegments(segment[1].item[0].tokens).join(', ') + ']'; // XXX alignStruct?
} else if (segment.length == 2) {
return parseNumerical(toNiceIdent(segment[1].text));
} else {
throw 'Invalid segment: ' + dump(segment);
}
};
- return splitTokenList(tokens).map(handleSegment).map(parseNumerical).join(', ');
+ return splitTokenList(tokens).map(handleSegment).map(parseNumerical);
}
if (value.item) {
// list of items
- return makePointer('[ ' + handleSegments(value.item[0].tokens) + ' ]');
+ return makePointer('[ ' + alignStruct(handleSegments(value.item[0].tokens), type).join(', ') + ' ]');
} else if (value.type == '{') {
// struct
- return makePointer('[ ' + handleSegments(value.tokens) + ' ]');
+ return makePointer('[ ' + alignStruct(handleSegments(value.tokens), type).join(', ') + ' ]');
} else if (value[0]) {
- return makePointer('[ ' + handleSegments(value[0].tokens) + ' ]');
+ return makePointer('[ ' + alignStruct(handleSegments(value[0].tokens), type).join(', ') + ' ]');
} else {
throw '// failzzzzzzzzzzzzzz ' + dump(value.item) + ' ::: ' + dump(value);
}
@@ -571,7 +600,11 @@ function JSify(data) {
var indexes = [makeGetPos(ident)];
var offset = toNiceIdent(item.params[1].ident);
if (offset != 0) {
- indexes.push((isStructType(type) && TYPES[type].flatSize != 1 ? TYPES[type].flatSize + '*' : '') + offset);
+ if (isStructType(type)) {
+ indexes.push((TYPES[type].flatSize != 1 ? TYPES[type].flatSize + '*' : '') + offset);
+ } else {
+ indexes.push(getNativeFieldSize(type, true) + '*' + offset);
+ }
}
item.params.slice(2, item.params.length).forEach(function(arg) {
var curr = toNiceIdent(arg.ident);
@@ -585,7 +618,7 @@ function JSify(data) {
}
} else {
if (curr != 0) {
- indexes.push(curr);
+ indexes.push(curr); // XXX QUANTUM_SIZE?
}
}
type = TYPES[type] ? TYPES[type].fields[curr] : '';
@@ -669,7 +702,8 @@ function JSify(data) {
substrate.addItems(data.functions, 'FunctionSplitter');
substrate.addItems(data.functionStubs, 'FunctionStub');
- return preprocess(read('preamble.js')) + finalCombiner(substrate.solve()) + read('postamble.js');
+ var params = { 'QUANTUM_SIZE': QUANTUM_SIZE };
+ return preprocess(read('preamble.js'), params) + finalCombiner(substrate.solve()) + preprocess(read('postamble.js'), params);
// return finalCombiner(substrate.solve());
}
diff --git a/src/parseTools.js b/src/parseTools.js
index cdd20e2f..5d868920 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -1,8 +1,11 @@
// Various tools for parsing llvm
// Simple #if/else/endif preprocessing for a file. Checks if the
-// ident checked is true in our global.
-function preprocess(text) {
+// ident checked is true in our global. Also replaces some constants
+function preprocess(text, constants) {
+ for (constant in constants) {
+ text = text.replace(eval('/' + constant + '/g'), constants[constant]);
+ }
var lines = text.split('\n');
var ret = '';
var show = true;
@@ -375,3 +378,28 @@ function getLabelIds(labels) {
return labels.map(function(label) { return label.ident });
}
+//! Returns the size of a field, as C/C++ would have it (in 32-bit,
+//! for now).
+//! @param field The field type, by name
+//! @param alone Whether this is inside a structure (so padding is
+//! used) or alone (line in char*, where no padding is done).
+function getNativeFieldSize(field, alone) {
+ var size;
+ if (QUANTUM_SIZE > 1) {
+ size = {
+ 'i1': alone ? 1 : 4, // inside a struct, aligned to 4,
+ 'i8': alone ? 1 : 4, // most likely...? XXX
+ 'i32': 4,
+ 'i64': 8,
+ 'float': 4,
+ 'double':8,
+ }[field]; // XXX 32/64 bit stuff
+ if (!size) {
+ size = 4; // Must be a pointer XXX 32/64
+ }
+ } else {
+ size = 1;
+ }
+ return size;
+}
+
diff --git a/src/postamble.js b/src/postamble.js
index c156cd21..a34370b2 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -3,9 +3,16 @@
function run(args) {
var argc = args.length+1;
+ function pad() {
+ for (var i = 0; i < QUANTUM_SIZE-1; i++) {
+ argv.push(0);
+ }
+ }
var argv = [Pointer_make(intArrayFromString("/bin/this.program")) ];
+ pad();
for (var i = 0; i < argc-1; i = i + 1) {
argv.push(Pointer_make(intArrayFromString(args[i])));
+ pad();
}
argv = Pointer_make(argv);
diff --git a/src/preamble.js b/src/preamble.js
index e458384d..f53f50ad 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -8,8 +8,10 @@ var __THREW__ = false; // Used in checking for thrown exceptions.
var __ATEXIT__ = [];
-var HEAP = intArrayFromString('(null)'); // So printing %s of NULL gives '(null)'
-var HEAPTOP = HEAP.length+1; // Leave 0 as an invalid address, 'NULL'
+var HEAP = [];
+var HEAPTOP = 0;
+Pointer_make(intArrayFromString('(null)')); // So printing %s of NULL gives '(null)'
+ // Also this ensures we leave 0 as an invalid address, 'NULL'
#if SAFE_HEAP
// Semi-manual memory corruption debugging
@@ -89,14 +91,16 @@ function Pointer_stringify(ptr) {
if ((ptr.pos+i) >= ptr.slab.length) { break; } else {}
t = String.fromCharCode(ptr.slab[ptr.pos + i]);
if (t == "\0") { break; } else {}
- ret = ret + t;
- i = i + 1;
+ ret += t;
+ i += 1;
}
return ret;
}
function _malloc(size) {
// XXX hardcoded ptr impl
+ size = Math.ceil(size/QUANTUM_SIZE)*QUANTUM_SIZE; // Allocate blocks of proper minimum size
+ // Also keeps HEAPTOP aligned
var ret = HEAPTOP;
HEAPTOP += size;
return ret;
@@ -139,7 +143,7 @@ function __formatString() {
if (curr == '%'.charCodeAt(0) && ['d', 'f', '.'].indexOf(String.fromCharCode(next)) != -1) {
var argText = String(arguments[argIndex]);
// Handle very very simply formatting, namely only %.Xf
- if (HEAP[textIndex+1] == '.'.charCodeAt(0)) {
+ if (next == '.'.charCodeAt(0)) {
var limit = parseInt(String.fromCharCode(HEAP[textIndex+2]));
var dotIndex = argText.indexOf('.');
argText = argText.substr(0, dotIndex+1+limit);
@@ -156,7 +160,7 @@ function __formatString() {
textIndex += 2;
} else {
ret.push(curr);
- textIndex ++;
+ textIndex += 1;
}
}
return Pointer_make(ret);
diff --git a/src/settings.js b/src/settings.js
index f84391fd..f6282ed4 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -1,3 +1,18 @@
+// Tuning
+QUANTUM_SIZE = 1; // This is the size of an individual field in a structure. 1 would
+ // lead to e.g. doubles and chars both taking 1 memory address. This
+ // is a form of 'compressed' memory, with shrinking and stretching
+ // according to the type, when compared to C/C++. On the other hand
+ // 8 means all fields take 8 memory addresses, so a double takes
+ // the same as a char. Note that we only actually store something in
+ // the top address - the others are just empty, an 'alignment cost'
+ // of sorts.
+ //
+ // llvm-gcc works with 1. However, clang uses llvm_memcpy for various
+ // things, and the number of bytes it copies is hardcoded. A simple
+ // way to prevent problems with that is to set QUANTUM_SIZE to 8.
+ // See the 'copyop' automatic test.
+
// Code embetterments
OPTIMIZE = 1; // Optimize llvm operations into js commands
RELOOP = 0; // Recreate js native loops from llvm data XXX - disabled pending optimizing rewrite
diff --git a/src/utility.js b/src/utility.js
index e4f20b7e..8907eb91 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -79,6 +79,12 @@ function range(size) {
return ret;
}
+function zeros(size) {
+ var ret = [];
+ for (var i = 0; i < size; i++) ret.push(0);
+ return ret;
+}
+
function searchable() {
if (typeof arguments[0] === 'object') arguments = arguments[0];
var ret = {};