aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jsifier.js84
-rw-r--r--src/library_browser.js31
-rw-r--r--src/library_glut.js37
-rw-r--r--src/parseTools.js16
-rw-r--r--src/relooper/Relooper.cpp74
-rw-r--r--src/relooper/Relooper.h2
-rw-r--r--src/settings.js9
-rw-r--r--src/shell.html6
8 files changed, 154 insertions, 105 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index ac6c259b..14c9cfbe 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -285,42 +285,60 @@ function JSify(data, functionsOnly, givenFunctions) {
index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this
allocator = 'ALLOC_NONE';
}
- if (item.external) {
- if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
- constant = zeros(Runtime.getNativeFieldSize(item.type));
- } else {
- constant = makeEmptyStruct(item.type);
+
+ if (isBSS(item)) {
+ var length = calcAllocatedSize(item.type);
+ length = Runtime.alignMemory(length);
+
+ // If using indexed globals, go ahead and early out (no need to explicitly
+ // initialize).
+ if (!NAMED_GLOBALS) {
+ return ret;
+ }
+ // If using named globals, we can at least shorten the call to allocate by
+ // passing an integer representing the size of memory to alloc instead of
+ // an array of 0s of size length.
+ else {
+ constant = length;
}
} else {
- constant = parseConst(item.value, item.type, item.ident);
- }
- assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
-
- // This is a flattened object. We need to find its idents, so they can be assigned to later
- constant.forEach(function(value, i) {
- if (needsPostSet(value)) { // ident, or expression containing an ident
- ret.push({
- intertype: 'GlobalVariablePostSet',
- JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
- });
- constant[i] = '0';
+ if (item.external) {
+ if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
+ constant = zeros(Runtime.getNativeFieldSize(item.type));
+ } else {
+ constant = makeEmptyStruct(item.type);
+ }
+ } else {
+ constant = parseConst(item.value, item.type, item.ident);
}
- });
+ assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
+
+ // This is a flattened object. We need to find its idents, so they can be assigned to later
+ constant.forEach(function(value, i) {
+ if (needsPostSet(value)) { // ident, or expression containing an ident
+ ret.push({
+ intertype: 'GlobalVariablePostSet',
+ JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
+ });
+ constant[i] = '0';
+ }
+ });
- if (item.external) {
- // External variables in shared libraries should not be declared as
- // they would shadow similarly-named globals in the parent, so do nothing here.
- if (BUILD_AS_SHARED_LIB) return ret;
- // Library items need us to emit something, but everything else requires nothing.
- if (!LibraryManager.library[item.ident.slice(1)]) return ret;
- }
+ if (item.external) {
+ // External variables in shared libraries should not be declared as
+ // they would shadow similarly-named globals in the parent, so do nothing here.
+ if (BUILD_AS_SHARED_LIB) return ret;
+ // Library items need us to emit something, but everything else requires nothing.
+ if (!LibraryManager.library[item.ident.slice(1)]) return ret;
+ }
- // ensure alignment
- constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length));
+ // ensure alignment
+ constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length));
- // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
- if (item.ident.substr(0, 5) == '__ZTV') {
- constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE)));
+ // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
+ if (item.ident.substr(0, 5) == '__ZTV') {
+ constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE)));
+ }
}
// NOTE: This is the only place that could potentially create static
@@ -695,7 +713,9 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
i++;
- return JS + (Debugging.on ? Debugging.getComment(line.lineNum) : '');
+ // invoke instructions span two lines, and the debug info is located
+ // on the second line, hence the +1
+ return JS + (Debugging.on ? Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0)) : '');
})
.join('\n')
.split('\n') // some lines include line breaks
@@ -1566,7 +1586,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
}
var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable);
- print(generated.map(function(item) { return item.JS }).join('\n'));
+ print(generated.map(function(item) { return item.JS; }).join('\n'));
if (phase == 'pre') {
if (memoryInitialization.length > 0) {
diff --git a/src/library_browser.js b/src/library_browser.js
index 925b64e2..d007d9a7 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -426,8 +426,17 @@ mergeInto(LibraryManager.library, {
Browser.mouseMovementX = Browser.getMovementX(event);
Browser.mouseMovementY = Browser.getMovementY(event);
}
- Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
- Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+
+ // check if SDL is available
+ if (typeof SDL != "undefined") {
+ Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+ Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+ } else {
+ // just add the mouse delta to the current absolut mouse position
+ // FIXME: ideally this should be clamped against the canvas size and zero
+ Browser.mouseX += Browser.mouseMovementX;
+ Browser.mouseY += Browser.mouseMovementY;
+ }
} else {
// Otherwise, calculate the movement based on the changes
// in the coordinates.
@@ -504,9 +513,12 @@ mergeInto(LibraryManager.library, {
this.windowedHeight = canvas.height;
canvas.width = screen.width;
canvas.height = screen.height;
- var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
- flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
- {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
+ // check if SDL is available
+ if (typeof SDL != "undefined") {
+ var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
+ flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+ {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
+ }
Browser.updateResizeListeners();
},
@@ -514,9 +526,12 @@ mergeInto(LibraryManager.library, {
var canvas = Module['canvas'];
canvas.width = this.windowedWidth;
canvas.height = this.windowedHeight;
- var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
- flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
- {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
+ // check if SDL is available
+ if (typeof SDL != "undefined") {
+ var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
+ flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+ {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
+ }
Browser.updateResizeListeners();
}
diff --git a/src/library_glut.js b/src/library_glut.js
index 38cfe55b..36d47787 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -117,9 +117,9 @@ var LibraryGLUT = {
if (48 <= keycode && keycode <= 57)
return keycode; // numeric TODO handle shift?
if (65 <= keycode && keycode <= 90)
- return event['shiftKey'] ? keycode : keycode + 32;
+ return event['shiftKey'] ? keycode : keycode + 32;
if (106 <= keycode && keycode <= 111)
- return keycode - 106 + 42; // *,+-./ TODO handle shift?
+ return keycode - 106 + 42; // *,+-./ TODO handle shift?
switch (keycode) {
case 27: // escape
@@ -227,7 +227,7 @@ var LibraryGLUT = {
} else {
width = GLUT.windowWidth;
height = GLUT.windowHeight;
- // TODO set position
+ // TODO set position
document.removeEventListener('fullscreenchange', GLUT.onFullScreenEventChange, true);
document.removeEventListener('mozfullscreenchange', GLUT.onFullScreenEventChange, true);
document.removeEventListener('webkitfullscreenchange', GLUT.onFullScreenEventChange, true);
@@ -255,13 +255,14 @@ var LibraryGLUT = {
document['cancelFullScreen'] ||
document['mozCancelFullScreen'] ||
document['webkitCancelFullScreen'] ||
- (function() {});
+ (function() {});
CFS.apply(document, []);
}
},
glutGetModifiers: function() { return GLUT.modifiers; },
+ glutInit__deps: ['$Browser'],
glutInit: function(argcp, argv) {
// Ignore arguments
GLUT.initTime = Date.now();
@@ -271,6 +272,12 @@ var LibraryGLUT = {
window.addEventListener("mousemove", GLUT.onMousemove, true);
window.addEventListener("mousedown", GLUT.onMouseButtonDown, true);
window.addEventListener("mouseup", GLUT.onMouseButtonUp, true);
+
+ Browser.resizeListeners.push(function(width, height) {
+ if (GLUT.reshapeFunc) {
+ Runtime.dynCall('vii', GLUT.reshapeFunc, [width, height]);
+ }
+ });
__ATEXIT__.push({ func: function() {
window.removeEventListener("keydown", GLUT.onKeydown, true);
@@ -294,21 +301,25 @@ var LibraryGLUT = {
glutGet: function(type) {
switch (type) {
case 100: /* GLUT_WINDOW_X */
- return 0; /* TODO */
+ return 0; /* TODO */
case 101: /* GLUT_WINDOW_Y */
- return 0; /* TODO */
+ return 0; /* TODO */
case 102: /* GLUT_WINDOW_WIDTH */
- return Module['canvas'].width;
+ return Module['canvas'].width;
case 103: /* GLUT_WINDOW_HEIGHT */
- return Module['canvas'].height;
+ return Module['canvas'].height;
+ case 200: /* GLUT_SCREEN_WIDTH */
+ return Module['canvas'].width;
+ case 201: /* GLUT_SCREEN_HEIGHT */
+ return Module['canvas'].height;
case 500: /* GLUT_INIT_WINDOW_X */
- return 0; /* TODO */
+ return 0; /* TODO */
case 501: /* GLUT_INIT_WINDOW_Y */
- return 0; /* TODO */
+ return 0; /* TODO */
case 502: /* GLUT_INIT_WINDOW_WIDTH */
- return GLUT.initWindowWidth;
+ return GLUT.initWindowWidth;
case 503: /* GLUT_INIT_WINDOW_HEIGHT */
- return GLUT.initWindowHeight;
+ return GLUT.initWindowHeight;
case 700: /* GLUT_ELAPSED_TIME */
var now = Date.now();
return now - GLUT.initTime;
@@ -386,10 +397,8 @@ var LibraryGLUT = {
glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'],
glutReshapeWindow: function(width, height) {
GLUT.cancelFullScreen();
- // console.log("glutReshapeWindow: " + width + ", " + height);
Browser.setCanvasSize(width, height);
if (GLUT.reshapeFunc) {
- // console.log("GLUT.reshapeFunc: " + width + ", " + height);
Runtime.dynCall('vii', GLUT.reshapeFunc, [width, height]);
}
_glutPostRedisplay();
diff --git a/src/parseTools.js b/src/parseTools.js
index 0b83a12b..babb2692 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -467,6 +467,17 @@ function isIndexableGlobal(ident) {
return !data.alias && !data.external;
}
+function isBSS(item) {
+ if (!USE_BSS) {
+ return false;
+ }
+
+ // return true if a global is uninitialized or initialized to 0
+ return item.external ||
+ (item.value && item.value.intertype === 'emptystruct') ||
+ (item.value && item.value.value !== undefined && item.value.value === '0');
+}
+
function makeGlobalDef(ident) {
if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '';
return 'var ' + ident + ';';
@@ -490,7 +501,10 @@ function sortGlobals(globals) {
ks.sort();
var inv = invertArray(ks);
return values(globals).sort(function(a, b) {
- return inv[b.ident] - inv[a.ident];
+ // sort globals based on if they need to be explicitly initialized or not (moving
+ // values that don't need to be to the end of the array). if equal, sort by name.
+ return (Number(isBSS(a)) - Number(isBSS(b))) ||
+ (inv[b.ident] - inv[a.ident]);
});
}
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp
index aa7e71a1..ca9c6ab1 100644
--- a/src/relooper/Relooper.cpp
+++ b/src/relooper/Relooper.cpp
@@ -10,6 +10,10 @@
// TODO: move all set to unorderedset
+template <class T, class U> bool contains(const T& container, const U& contained) {
+ return container.find(contained) != container.end();
+}
+
#if DEBUG
static void PrintDebug(const char *Format, ...);
#define DebugDump(x, ...) Debugging::Dump(x, __VA_ARGS__)
@@ -100,7 +104,7 @@ void Branch::Render(Block *Target, bool SetLabel) {
int Block::IdCounter = 1; // 0 is reserved for clearings
-Block::Block(const char *CodeInit) : Parent(NULL), Id(Block::IdCounter++), DefaultTarget(NULL), IsCheckedMultipleEntry(false) {
+Block::Block(const char *CodeInit) : Parent(NULL), Id(Block::IdCounter++), IsCheckedMultipleEntry(false) {
Code = strdup(CodeInit);
}
@@ -113,7 +117,7 @@ Block::~Block() {
}
void Block::AddBranchTo(Block *Target, const char *Condition, const char *Code) {
- assert(BranchesOut.find(Target) == BranchesOut.end()); // cannot add more than one branch to the same target
+ assert(!contains(BranchesOut, Target)); // cannot add more than one branch to the same target
BranchesOut[Target] = new Branch(Condition, Code);
}
@@ -174,6 +178,8 @@ void Block::Render(bool InLoop) {
}
}
+ Block *DefaultTarget(NULL); // The block we branch to without checking the condition, if none of the other conditions held.
+
// We must do this here, because blocks can be split and even comparing their Ids is not enough. We must check the conditions.
for (BlockBranchMap::iterator iter = ProcessedBranchesOut.begin(); iter != ProcessedBranchesOut.end(); iter++) {
if (!iter->second->Condition) {
@@ -181,7 +187,7 @@ void Block::Render(bool InLoop) {
DefaultTarget = iter->first;
}
}
- assert(DefaultTarget); // Must be a default
+ assert(DefaultTarget); // Since each block *must* branch somewhere, this must be set
ministring RemainingConditions;
bool First = true;
@@ -198,7 +204,7 @@ void Block::Render(bool InLoop) {
Details = ProcessedBranchesOut[DefaultTarget];
}
bool SetCurrLabel = SetLabel && Target->IsCheckedMultipleEntry;
- bool HasFusedContent = Fused && Fused->InnerMap.find(Target) != Fused->InnerMap.end();
+ bool HasFusedContent = Fused && contains(Fused->InnerMap, Target);
bool HasContent = SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code;
if (iter != ProcessedBranchesOut.end()) {
// If there is nothing to show in this branch, omit the condition
@@ -356,7 +362,7 @@ void Relooper::Calculate(Block *Entry) {
while (ToInvestigate.size() > 0) {
Block *Curr = ToInvestigate.front();
ToInvestigate.pop_front();
- if (Live.find(Curr) != Live.end()) continue;
+ if (contains(Live, Curr)) continue;
Live.insert(Curr);
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
ToInvestigate.push_back(iter->first);
@@ -380,7 +386,7 @@ void Relooper::Calculate(Block *Entry) {
for (BlockSet::iterator iter = Live.begin(); iter != Live.end(); iter++) {
Block *Original = *iter;
if (Original->BranchesIn.size() <= 1 || Original->BranchesOut.size() > 0) continue; // only dead ends, for now
- if (Original->BranchesOut.find(Original) != Original->BranchesOut.end()) continue; // cannot split a looping node
+ if (contains(Original->BranchesOut, Original)) continue; // cannot split a looping node
if (strlen(Original->Code)*(Original->BranchesIn.size()-1) > TotalCodeSize/5) continue; // if splitting increases raw code size by a significant amount, abort
// Split the node (for simplicity, we replace all the blocks, even though we could have reused the original)
PrintDebug("Splitting block %d\n", Original->Id);
@@ -423,7 +429,7 @@ void Relooper::Calculate(Block *Entry) {
// Add incoming branches from live blocks, ignoring dead code
for (int i = 0; i < Blocks.size(); i++) {
Block *Curr = Blocks[i];
- if (Pre.Live.find(Curr) == Pre.Live.end()) continue;
+ if (!contains(Pre.Live, Curr)) continue;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
iter->first->BranchesIn.insert(Curr);
}
@@ -445,7 +451,7 @@ void Relooper::Calculate(Block *Entry) {
// will appear
void GetBlocksOut(Block *Source, BlockSet& Entries, BlockSet *LimitTo=NULL) {
for (BlockBranchMap::iterator iter = Source->BranchesOut.begin(); iter != Source->BranchesOut.end(); iter++) {
- if (!LimitTo || LimitTo->find(iter->first) != LimitTo->end()) {
+ if (!LimitTo || contains(*LimitTo, iter->first)) {
Entries.insert(iter->first);
}
}
@@ -457,7 +463,7 @@ void Relooper::Calculate(Block *Entry) {
DebugDump(From, " relevant to solipsize: ");
for (BlockSet::iterator iter = Target->BranchesIn.begin(); iter != Target->BranchesIn.end();) {
Block *Prior = *iter;
- if (From.find(Prior) == From.end()) {
+ if (!contains(From, Prior)) {
iter++;
continue;
}
@@ -502,7 +508,7 @@ void Relooper::Calculate(Block *Entry) {
while (Queue.size() > 0) {
Block *Curr = *(Queue.begin());
Queue.erase(Queue.begin());
- if (InnerBlocks.find(Curr) == InnerBlocks.end()) {
+ if (!contains(InnerBlocks, Curr)) {
// This element is new, mark it as inner and remove from outer
InnerBlocks.insert(Curr);
Blocks.erase(Curr);
@@ -518,7 +524,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Curr = *iter;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
Block *Possible = iter->first;
- if (InnerBlocks.find(Possible) == InnerBlocks.end()) {
+ if (!contains(InnerBlocks, Possible)) {
NextEntries.insert(Possible);
}
}
@@ -615,7 +621,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Invalidatee = ToInvalidate.front();
ToInvalidate.pop_front();
Block *Owner = Ownership[Invalidatee];
- if (IndependentGroups.find(Owner) != IndependentGroups.end()) { // Owner may have been invalidated, do not add to IndependentGroups!
+ if (contains(IndependentGroups, Owner)) { // Owner may have been invalidated, do not add to IndependentGroups!
IndependentGroups[Owner].erase(Invalidatee);
}
if (Ownership[Invalidatee]) { // may have been seen before and invalidated already
@@ -688,7 +694,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Child = *iter;
for (BlockSet::iterator iter = Child->BranchesIn.begin(); iter != Child->BranchesIn.end(); iter++) {
Block *Parent = *iter;
- if (Ignore && Ignore->find(Parent) != Ignore->end()) continue;
+ if (Ignore && contains(*Ignore, Parent)) continue;
if (Helper.Ownership[Parent] != Helper.Ownership[Child]) {
ToInvalidate.push_back(Child);
}
@@ -739,7 +745,7 @@ void Relooper::Calculate(Block *Entry) {
Block *CurrTarget = iter->first;
BlockBranchMap::iterator Next = iter;
Next++;
- if (CurrBlocks.find(CurrTarget) == CurrBlocks.end()) {
+ if (!contains(CurrBlocks, CurrTarget)) {
NextEntries.insert(CurrTarget);
Solipsize(CurrTarget, Branch::Break, Multiple, CurrBlocks);
}
@@ -756,7 +762,7 @@ void Relooper::Calculate(Block *Entry) {
// Add entries not handled as next entries, they are deferred
for (BlockSet::iterator iter = Entries.begin(); iter != Entries.end(); iter++) {
Block *Entry = *iter;
- if (IndependentGroups.find(Entry) == IndependentGroups.end()) {
+ if (!contains(IndependentGroups, Entry)) {
NextEntries.insert(Entry);
}
}
@@ -820,7 +826,7 @@ void Relooper::Calculate(Block *Entry) {
BlockBlockSetMap::iterator curr = iter++; // iterate carefully, we may delete
for (BlockSet::iterator iterBranch = Entry->BranchesIn.begin(); iterBranch != Entry->BranchesIn.end(); iterBranch++) {
Block *Origin = *iterBranch;
- if (Group.find(Origin) == Group.end()) {
+ if (!contains(Group, Origin)) {
// Reached from outside the group, so we cannot handle this
PrintDebug("Cannot handle group with entry %d because of incoming branch from %d\n", Entry->Id, Origin->Id);
IndependentGroups.erase(curr);
@@ -858,7 +864,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Curr = *iter;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
Block *Target = iter->first;
- if (SmallGroup.find(Target) == SmallGroup.end()) {
+ if (!contains(SmallGroup, Target)) {
DeadEnd = false;
break;
}
@@ -909,13 +915,13 @@ void Relooper::Calculate(Block *Entry) {
PostOptimizer(Relooper *ParentInit) : Parent(ParentInit), Closure(NULL) {}
- #define RECURSE_MULTIPLE_MANUAL(func, manual) \
- for (BlockShapeMap::iterator iter = manual->InnerMap.begin(); iter != manual->InnerMap.end(); iter++) { \
+ #define RECURSE_Multiple(shape, func) \
+ for (BlockShapeMap::iterator iter = shape->InnerMap.begin(); iter != shape->InnerMap.end(); iter++) { \
func(iter->second); \
}
- #define RECURSE_MULTIPLE(func) RECURSE_MULTIPLE_MANUAL(func, Multiple);
- #define RECURSE_LOOP(func) \
- func(Loop->Inner);
+ #define RECURSE_Loop(shape, func) \
+ func(shape->Inner);
+ #define RECURSE(shape, func) RECURSE_##shape(shape, func);
#define SHAPE_SWITCH(var, simple, multiple, loop) \
if (SimpleShape *Simple = Shape::IsSimple(var)) { \
@@ -926,20 +932,6 @@ void Relooper::Calculate(Block *Entry) {
loop; \
}
- #define SHAPE_SWITCH_AUTO(var, simple, multiple, loop, func) \
- if (SimpleShape *Simple = Shape::IsSimple(var)) { \
- simple; \
- func(Simple->Next); \
- } else if (MultipleShape *Multiple = Shape::IsMultiple(var)) { \
- multiple; \
- RECURSE_MULTIPLE(func) \
- func(Multiple->Next); \
- } else if (LoopShape *Loop = Shape::IsLoop(var)) { \
- loop; \
- RECURSE_LOOP(func); \
- func(Loop->Next); \
- }
-
// Find the blocks that natural control flow can get us directly to, or through a multiple that we ignore
void FollowNaturalFlow(Shape *S, BlockSet &Out) {
SHAPE_SWITCH(S, {
@@ -992,7 +984,7 @@ void Relooper::Calculate(Block *Entry) {
for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) {
Block *Target = iter->first;
Branch *Details = iter->second;
- if (Details->Type != Branch::Direct && NaturalBlocks.find(Target) != NaturalBlocks.end()) { // note: cannot handle split blocks
+ if (Details->Type != Branch::Direct && contains(NaturalBlocks, Target)) { // note: cannot handle split blocks
Details->Type = Branch::Direct;
if (MultipleShape *Multiple = Shape::IsMultiple(Details->Ancestor)) {
Multiple->NeedLoop--;
@@ -1036,7 +1028,7 @@ void Relooper::Calculate(Block *Entry) {
// If we are fusing a Multiple with a loop into this Simple, then visit it now
if (Fused && Fused->NeedLoop) {
LoopStack.push(Fused);
- RECURSE_MULTIPLE_MANUAL(FindLabeledLoops, Fused);
+ RECURSE_Multiple(Fused, FindLabeledLoops);
}
for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) {
Block *Target = iter->first;
@@ -1062,14 +1054,14 @@ void Relooper::Calculate(Block *Entry) {
if (Multiple->NeedLoop) {
LoopStack.push(Multiple);
}
- RECURSE_MULTIPLE(FindLabeledLoops);
+ RECURSE(Multiple, FindLabeledLoops);
if (Multiple->NeedLoop) {
LoopStack.pop();
}
Next = Root->Next;
}, {
LoopStack.push(Loop);
- RECURSE_LOOP(FindLabeledLoops);
+ RECURSE(Loop, FindLabeledLoops);
LoopStack.pop();
Next = Root->Next;
});
@@ -1123,7 +1115,7 @@ void Debugging::Dump(BlockSet &Blocks, const char *prefix) {
for (BlockBranchMap::iterator iter2 = Curr->BranchesOut.begin(); iter2 != Curr->BranchesOut.end(); iter2++) {
Block *Other = iter2->first;
printf(" -> %d\n", Other->Id);
- assert(Other->BranchesIn.find(Curr) != Other->BranchesIn.end());
+ assert(contains(Other->BranchesIn, Curr));
}
}
}
diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h
index fe56a133..e54b578c 100644
--- a/src/relooper/Relooper.h
+++ b/src/relooper/Relooper.h
@@ -59,8 +59,6 @@ struct Block {
Shape *Parent; // The shape we are directly inside
int Id; // A unique identifier
const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input)
- Block *DefaultTarget; // The block we branch to without checking the condition, if none of the other conditions held.
- // Since each block *must* branch somewhere, this must be set
bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable
Block(const char *CodeInit);
diff --git a/src/settings.js b/src/settings.js
index 3a91b488..4b6f033b 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -67,9 +67,9 @@ var RELOOP = 0; // Recreate js native loops from llvm data
var RELOOPER = 'relooper.js'; // Loads the relooper from this path relative to compiler.js
var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap. See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/
- // 0 means no typed arrays are used.
+ // 0 means no typed arrays are used. This mode disallows LLVM optimizations
// 1 has two heaps, IHEAP (int32) and FHEAP (double),
- // and addresses there are a match for normal addresses. This is deprecated.
+ // and addresses there are a match for normal addresses. This mode disallows LLVM optimizations.
// 2 is a single heap, accessible through views as int8, int32, etc. This is
// the recommended mode both for performance and for compatibility.
var USE_FHEAP = 1; // Relevant in USE_TYPED_ARRAYS == 1. If this is disabled, only IHEAP will be used, and FHEAP
@@ -236,6 +236,11 @@ var FS_LOG = 0; // Log all FS operations. This is especially helpful when you'r
// a new project and want to see a list of file system operations happening
// so that you can create a virtual file system with all of the required files.
+var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss
+ // When enabled, 0-initialized globals are sorted to the end of the globals list,
+ // enabling us to not explicitly store the initialization value for each 0 byte.
+ // This significantly lowers the memory initialization array size.
+
var NAMED_GLOBALS = 0; // If 1, we use global variables for globals. Otherwise
// they are referred to by a base plus an offset (called an indexed global),
// saving global variables but adding runtime overhead.
diff --git a/src/shell.html b/src/shell.html
index f7eb9e1f..00765271 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -87,10 +87,6 @@
};
Module.setStatus('Downloading...');
</script>
- <script type='text/javascript'>
-
- {{{ SCRIPT_CODE }}}
-
- </script>
+ <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script>
</body>
</html>