diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 128 | ||||
-rw-r--r-- | src/compiler.js | 2 | ||||
-rw-r--r-- | src/experimental/stringCache.diff | 147 | ||||
-rw-r--r-- | src/intertyper.js | 4 | ||||
-rw-r--r-- | src/jsifier.js | 47 | ||||
-rw-r--r-- | src/library.js | 183 | ||||
-rw-r--r-- | src/library_browser.js | 314 | ||||
-rw-r--r-- | src/library_gc.js | 165 | ||||
-rw-r--r-- | src/library_gl.js | 1114 | ||||
-rw-r--r-- | src/library_glut.js | 20 | ||||
-rw-r--r-- | src/library_sdl.js | 324 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 52 | ||||
-rw-r--r-- | src/postamble.js | 46 | ||||
-rw-r--r-- | src/preamble.js | 7 | ||||
-rw-r--r-- | src/runtime.js | 71 | ||||
-rw-r--r-- | src/settings.js | 21 | ||||
-rw-r--r-- | src/shell.html | 48 | ||||
-rw-r--r-- | src/utility.js | 4 |
19 files changed, 1942 insertions, 757 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 8ded86f1..4bf2255e 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -9,7 +9,7 @@ var VAR_NATIVIZED = 'nativized'; var VAR_EMULATED = 'emulated'; var ENTRY_IDENT = toNiceIdent('%0'); -var ENTRY_IDENTS = set(toNiceIdent('%0'), toNiceIdent('%1')); +var ENTRY_IDENT_IDS = set(0, 1); // XXX function recomputeLines(func) { func.lines = func.labels.map(function(label) { return label.lines }).reduce(concatenator, []); @@ -544,6 +544,10 @@ function analyzer(data, sidePass) { params: [(signed && j + whole > sourceElements.length) ? signedKeepAlive : null], type: 'i32', }; + if (j == 0 && isUnsignedOp(value.op) && sourceBits < 32) { + // zext sign correction + result.ident = makeSignOp(result.ident, 'i' + sourceBits, 'un', 1, 1); + } if (fraction != 0) { var other = { intertype: 'value', @@ -1176,7 +1180,9 @@ function analyzer(data, sidePass) { func.labelIdsInverse = {}; func.labelIds[toNiceIdent('%0')] = 0; func.labelIdsInverse[0] = toNiceIdent('%0'); - func.labelIdCounter = 1; + func.labelIds[toNiceIdent('%1')] = 1; + func.labelIdsInverse[1] = toNiceIdent('%1'); + func.labelIdCounter = 2; func.labels.forEach(function(label) { func.labelIds[label.ident] = func.labelIdCounter++; func.labelIdsInverse[func.labelIdCounter-1] = label.ident; @@ -1202,6 +1208,7 @@ function analyzer(data, sidePass) { if (phi.intertype == 'phi') { for (var i = 0; i < phi.params.length; i++) { phi.params[i].label = func.labelIds[phi.params[i].label]; + if (!phi.params[i].label) warn('phi refers to nonexistent label on line ' + phi.lineNum); } } }); @@ -1217,9 +1224,10 @@ function analyzer(data, sidePass) { // So we need to handle that in a special way here. function getActualLabelId(labelId) { if (func.labelsDict[labelId]) return labelId; - if (labelId in ENTRY_IDENTS) { - assert(func.labelsDict[ENTRY_IDENT]); - return ENTRY_IDENT; + if (labelId in ENTRY_IDENT_IDS) { + labelId = func.labelIds[ENTRY_IDENT]; + assert(func.labelsDict[labelId]); + return labelId; } return null; } @@ -1270,88 +1278,44 @@ function analyzer(data, sidePass) { recomputeLines(func); } - if (!MICRO_OPTS) { - // 'Emulate' phis, by doing an if where the phi appears in the .ll. For this - // we need __lastLabel__. - func.needsLastLabel = false; - func.labels.forEach(function(label) { - var phis = []; - label.lines.forEach(function(phi) { - if (phi.intertype == 'phi') { - for (var i = 0; i < phi.params.length; i++) { - var sourceLabelId = getActualLabelId(phi.params[i].label); - if (sourceLabelId) { - var sourceLabel = func.labelsDict[sourceLabelId]; - var lastLine = sourceLabel.lines.slice(-1)[0]; - assert(lastLine.intertype in LLVM.PHI_REACHERS, 'Only some can lead to labels with phis:' + [func.ident, label.ident, lastLine.intertype]); - lastLine.currLabelId = sourceLabelId; - } - } - phis.push(phi); - func.needsLastLabel = true; - } - }); + // Properly implement phis, by pushing them back into the branch + // that leads to here. We will only have the |var| definition in this location. - if (phis.length >= 2) { - // Multiple phis have the semantics that they all occur 'in parallel', i.e., changes to - // a variable that is the result of a phi should *not* affect the other results. We must - // therefore be careful! - phis[phis.length-1].postSet = '; /* post-phi: */'; - for (var i = 0; i < phis.length-1; i++) { - var ident = phis[i].assignTo; - var phid = ident+'$phi' - phis[phis.length-1].postSet += ident + '=' + phid + ';'; - phis[i].assignTo = phid; - func.variables[phid] = { - ident: phid, - type: func.variables[ident].type, - origin: func.variables[ident].origin, - lineNum: func.variables[ident].lineNum, - uses: 1, - impl: VAR_EMULATED - }; - } - } - }); - } else { - // MICRO_OPTS == 1: Properly implement phis, by pushing them back into the branch - // that leads to here. We will only have the |var| definition in this location. - - // First, push phis back - func.labels.forEach(function(label) { - label.lines.forEach(function(phi) { - if (phi.intertype == 'phi') { - for (var i = 0; i < phi.params.length; i++) { - var param = phi.params[i]; - var sourceLabelId = getActualLabelId(param.label); - if (sourceLabelId) { - var sourceLabel = func.labelsDict[sourceLabelId]; - var lastLine = sourceLabel.lines.slice(-1)[0]; - assert(lastLine.intertype in LLVM.PHI_REACHERS, 'Only some can lead to labels with phis:' + [func.ident, label.ident, lastLine.intertype]); - if (!lastLine.phi) { - lastLine.phi = true; - assert(!lastLine.dependent); - lastLine.dependent = { - intertype: 'phiassigns', - params: [] - }; + // First, push phis back + func.labels.forEach(function(label) { + label.lines.forEach(function(phi) { + if (phi.intertype == 'phi') { + for (var i = 0; i < phi.params.length; i++) { + var param = phi.params[i]; + if (!param.label) warn('phi refers to nonexistent label on line ' + phi.lineNum); + var sourceLabelId = getActualLabelId(param.label); + if (sourceLabelId) { + var sourceLabel = func.labelsDict[sourceLabelId]; + var lastLine = sourceLabel.lines.slice(-1)[0]; + assert(lastLine.intertype in LLVM.PHI_REACHERS, 'Only some can lead to labels with phis:' + [func.ident, label.ident, lastLine.intertype]); + if (!lastLine.phi) { + lastLine.phi = true; + assert(!lastLine.dependent); + lastLine.dependent = { + intertype: 'phiassigns', + params: [] }; - lastLine.dependent.params.push({ - intertype: 'phiassign', - ident: phi.assignTo, - value: param.value, - targetLabel: label.ident - }); - } + }; + lastLine.dependent.params.push({ + intertype: 'phiassign', + ident: phi.assignTo, + value: param.value, + targetLabel: label.ident + }); } - // The assign to phi is now just a var - phi.intertype = 'var'; - phi.ident = phi.assignTo; - phi.assignTo = null; } - }); + // The assign to phi is now just a var + phi.intertype = 'var'; + phi.ident = phi.assignTo; + phi.assignTo = null; + } }); - } + }); }); this.forwardItem(item, 'StackAnalyzer'); } diff --git a/src/compiler.js b/src/compiler.js index 4442e38e..89da32d5 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -146,6 +146,8 @@ if (PGO) { // by default, correct everything during PGO EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); +RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; + // Settings sanity checks assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4'); diff --git a/src/experimental/stringCache.diff b/src/experimental/stringCache.diff new file mode 100644 index 00000000..26cbc68c --- /dev/null +++ b/src/experimental/stringCache.diff @@ -0,0 +1,147 @@ +diff --git a/src/library_gl.js b/src/library_gl.js +index 7471578..9228964 100644 +--- a/src/library_gl.js ++++ b/src/library_gl.js +@@ -1256,28 +1256,28 @@ var LibraryGL = { + + setClientAttribute: function(name, size, type, stride, pointer) { + var attrib = this.clientAttributes[GL.immediate.ATTRIBUTE_BY_NAME[name]]; + attrib.size = size; + attrib.type = type; + attrib.stride = stride; + attrib.pointer = pointer; +- attrib.name = name + size; ++ attrib.name = Runtime.getStringConcat(name, size); + }, + + // Renderers + addRendererComponent: function(component) { + if (this.rendererComponents[component]) return; + this.rendererComponents[component] = 1; +- this.renderer += component; ++ this.renderer = Runtime.getStringConcat(this.renderer, component); + }, + + setRenderer: function(renderer) { + var name = renderer; + if (GL.currProgram && renderer[0] != 'U') { +- name = 'UD' + GL.currProgram + '|' + renderer; // user-defined program renderer ++ name = Runtime.getStringConcat(Runtime.getStringConcat('UD', GL.currProgram), Runtime.getStringConcat('|', renderer)); // user-defined program renderer + } + this.renderer = name; + if (this.renderers[name]) return this.renderers[name]; + this.renderers[name] = this.createRenderer(renderer); + return this.renderers[name]; + }, + +@@ -1300,15 +1300,18 @@ var LibraryGL = { + } + vertexSize += size * 4; // XXX assuming float + } else if (which == 'N') { + vertexSize += 4; // 1 char, + alignment + } else if (which == 'C') { + vertexSize += 4; // Up to 4 chars, + alignment + } else { +- console.log('Warning: Ignoring renderer attribute ' + which); ++#if ASSERTIONS ++ console.log('Warning: Ignoring renderer attribute'); ++ console.log(which); ++#endif + size = parseInt(renderer[i+1]); + vertexSize += size * 4; // XXX assuming float + } + } + assert(positionSize > 0); + // TODO: verify vertexSize is equal to the stride in enabled client arrays + var useCurrProgram = !!GL.currProgram; +@@ -1465,30 +1468,30 @@ var LibraryGL = { + var renderer = '', bytes = 0; + for (var i = 0; i < attributes.length; i++) { + var attribute = attributes[i]; + if (!attribute) break; + attribute.offset = attribute.pointer - start; + if (attribute.offset > bytes) { // ensure we start where we should + assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment +- renderer += '?' + ((attribute.offset - bytes)/4); ++ renderer = Runtime.getStringConcat(renderer, Runtime.getStringConcat('?', ((attribute.offset - bytes)/4))); + bytes += attribute.offset - bytes; + } +- renderer += attribute.name; ++ renderer = Runtime.getStringConcat(renderer, attribute.name); + bytes += attribute.size * GL.immediate.byteSizeByType[attribute.type]; + if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment + #if ASSERTIONS + assert(0 <= attribute.offset && attribute.offset < stride); // must all be in the same buffer + #endif + } + + assert(stride == 0 || bytes <= stride); + + if (bytes < stride) { // ensure the size is that of the stride + assert((stride - bytes)%4 == 0); // assuming float +- renderer += '?' + ((stride-bytes)/4); ++ renderer = Runtime.getStringConcat(renderer, Runtime.getStringConcat('?', ((stride-bytes)/4))); + bytes = stride; + } + + bytes *= count; + if (!GL.currArrayBuffer) { + GL.immediate.vertexData = {{{ makeHEAPView('F32', 'start', 'start + bytes') }}}; // XXX assuming float + } +@@ -1671,15 +1674,15 @@ var LibraryGL = { + }, + + glVertexPointer__deps: ['$GLEmulation'], // if any pointers are used, glVertexPointer must be, and if it is, then we need emulation + glVertexPointer: function(size, type, stride, pointer) { + GL.immediate.setClientAttribute('V', size, type, stride, pointer); + }, + glTexCoordPointer: function(size, type, stride, pointer) { +- GL.immediate.setClientAttribute('T' + GL.immediate.clientActiveTexture, size, type, stride, pointer); ++ GL.immediate.setClientAttribute(Runtime.getStringConcat('T', GL.immediate.clientActiveTexture), size, type, stride, pointer); + }, + glNormalPointer: function(type, stride, pointer) { + GL.immediate.setClientAttribute('N', 1, type, stride, pointer); + }, + glColorPointer: function(size, type, stride, pointer) { + GL.immediate.setClientAttribute('C', size, type, stride, pointer); + }, +diff --git a/src/runtime.js b/src/runtime.js +index 6a251c4..012a66d 100644 +--- a/src/runtime.js ++++ b/src/runtime.js +@@ -319,25 +319,34 @@ var Runtime = { + if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {}; + if (!Runtime.warnOnce.shown[text]) { + Runtime.warnOnce.shown[text] = 1; + Module.printErr(text); + } + }, + ++ // Cache for JS function wrappers for C functions in FUNCTION_TABLE + funcWrappers: {}, +- + getFuncWrapper: function(func) { + if (!Runtime.funcWrappers[func]) { + Runtime.funcWrappers[func] = function() { + FUNCTION_TABLE[func].apply(null, arguments); + }; + } + return Runtime.funcWrappers[func]; + }, + ++ // Cache for small recurring strings generated by concatenating other ++ // strings, use this to avoid needless allocation and collection ++ stringCache: {}, ++ getStringConcat: function(a, b) { ++ var cacheItem = Runtime.stringCache[a]; ++ if (!cacheItem) cacheItem = Runtime.stringCache[a] = {}; ++ return cacheItem[b] || (cacheItem[b] = a + b); ++ }, ++ + #if RUNTIME_DEBUG + debug: true, // Switch to false at runtime to disable logging at the right times + + printObjectList: [], + + prettyPrint: function(arg) { + if (typeof arg == 'undefined') return '!UNDEFINED!'; diff --git a/src/intertyper.js b/src/intertyper.js index 0f9ce659..354ec19c 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -350,6 +350,10 @@ function intertyper(data, sidePass, baseLineNums) { return 'FuncHeader'; if (tokensLength >= 1 && token0Text == '}') return 'FuncEnd'; + if (token0Text == 'module' && token1Text == 'asm') { + warn('Ignoring module asm: ' + item.tokens[2].text); + return '/dev/null'; + } } if (tokensLength >= 3 && (token0Text == 'call' || token1Text == 'call')) return 'Call'; diff --git a/src/jsifier.js b/src/jsifier.js index 904517e1..b3c2af1d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -73,6 +73,9 @@ function JSify(data, functionsOnly, givenFunctions) { } else { libFuncsToInclude = ['memcpy', 'memset', 'malloc', 'free']; } + if (GENERATING_HTML) { + libFuncsToInclude.push('$Browser'); + } libFuncsToInclude.forEach(function(ident) { data.functionStubs.push({ intertype: 'functionStub', @@ -408,8 +411,8 @@ function JSify(data, functionsOnly, givenFunctions) { // name the function; overwrite if it's already named snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); if (LIBRARY_DEBUG) { - snippet = snippet.replace('{', '{ var ret = (function() {Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments) + "]"); '); - snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); Module.printErr(" [ return:" + ret); return ret; }'; + snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); + snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; }'; } } @@ -432,7 +435,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { ident = '_' + ident; } - var text = (deps ? '\n' + deps.map(addFromLibrary).join('\n') : ''); + var text = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); text += isFunction ? snippet : 'var ' + ident + '=' + snippet + ';'; if (ident in EXPORTED_FUNCTIONS) { text += '\nModule["' + ident + '"] = ' + ident + ';'; @@ -450,6 +453,9 @@ function JSify(data, functionsOnly, givenFunctions) { item.JS = addFromLibrary(shortident); } else { item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; + if (WARN_ON_UNDEFINED_SYMBOLS) { + warn('Unresolved symbol: ' + item.ident); + } } return ret; } @@ -555,9 +561,6 @@ function JSify(data, functionsOnly, givenFunctions) { if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */'; func.JS += ' var __label__;\n'; } - if (func.needsLastLabel) { - func.JS += ' var __lastLabel__ = null;\n'; - } // Walk function blocks and generate JS function walkBlock(block, indent) { @@ -748,7 +751,7 @@ function JSify(data, functionsOnly, givenFunctions) { makeFuncLineActor('noop', function(item) { return ';'; }); - makeFuncLineActor('var', function(item) { // assigns into phis become simple vars when MICRO_OPTS + makeFuncLineActor('var', function(item) { // assigns into phis become simple vars return 'var ' + item.ident + ';'; }); makeFuncLineActor('store', function(item) { @@ -789,11 +792,8 @@ function JSify(data, functionsOnly, givenFunctions) { return label; } - function makeBranch(label, lastLabel, labelIsVariable) { + function makeBranch(label, lastLabel, labelIsVariable) { // lastLabel is deprecated var pre = ''; - if (!MICRO_OPTS && lastLabel) { - pre = '__lastLabel__ = ' + getLabelId(lastLabel) + '; '; - } if (label[0] == 'B') { assert(!labelIsVariable, 'Cannot handle branches to variables with special branching options'); var parts = label.split('|'); @@ -1030,7 +1030,16 @@ function JSify(data, functionsOnly, givenFunctions) { makeFuncLineActor('extractvalue', function(item) { assert(item.indexes.length == 1); // TODO: use getelementptr parsing stuff, for depth. For now, we assume that LLVM aggregates are flat, // and we emulate them using simple JS objects { f1: , f2: , } etc., for speed - return item.ident + '.f' + item.indexes[0][0].text; + var index = item.indexes[0][0].text; + var valueType = Types.types[item.type].fields[index]; + if (USE_TYPED_ARRAYS != 2 || valueType != 'i64') { + return item.ident + '.f' + index; + } else { + var assignTo = item.assignTo; + item.assignTo = null; + return 'var ' + assignTo + '$0 = ' + item.ident + '.f' + index + '[0];' + + 'var ' + assignTo + '$1 = ' + item.ident + '.f' + index + '[1];'; + } }); makeFuncLineActor('insertvalue', function(item) { assert(item.indexes.length == 1); // TODO: see extractvalue @@ -1052,20 +1061,6 @@ function JSify(data, functionsOnly, givenFunctions) { return RuntimeGenerator.stackAlloc(getFastValue(calcAllocatedSize(item.allocatedType), '*', item.allocatedNum)); } }); - makeFuncLineActor('phi', function(item) { - var params = item.params; - assert(!MICRO_OPTS); - function makeOne(i) { - if (i === params.length-1) { - return finalizeLLVMParameter(params[i].value); - } - return '__lastLabel__ == ' + getLabelId(params[i].label) + ' ? ' + - finalizeLLVMParameter(params[i].value) + ' : (' + makeOne(i+1) + ')'; - } - var ret = makeOne(0); - if (item.postSet) ret += item.postSet; - return ret; - }); makeFuncLineActor('mathop', processMathop); diff --git a/src/library.js b/src/library.js index c491f078..2472e701 100644 --- a/src/library.js +++ b/src/library.js @@ -90,18 +90,18 @@ LibraryManager.library = { #if FS_LOG var inputPath = path; function log() { - print('FS.analyzePath("' + inputPath + '", ' + - dontResolveLastLink + ', ' + - linksVisited + ') => {' + - 'isRoot: ' + ret.isRoot + ', ' + - 'exists: ' + ret.exists + ', ' + - 'error: ' + ret.error + ', ' + - 'name: "' + ret.name + '", ' + - 'path: "' + ret.path + '", ' + - 'object: ' + ret.object + ', ' + - 'parentExists: ' + ret.parentExists + ', ' + - 'parentPath: "' + ret.parentPath + '", ' + - 'parentObject: ' + ret.parentObject + '}'); + Module['print']('FS.analyzePath("' + inputPath + '", ' + + dontResolveLastLink + ', ' + + linksVisited + ') => {' + + 'isRoot: ' + ret.isRoot + ', ' + + 'exists: ' + ret.exists + ', ' + + 'error: ' + ret.error + ', ' + + 'name: "' + ret.name + '", ' + + 'path: "' + ret.path + '", ' + + 'object: ' + ret.object + ', ' + + 'parentExists: ' + ret.parentExists + ', ' + + 'parentPath: "' + ret.parentPath + '", ' + + 'parentObject: ' + ret.parentObject + '}'); } #endif path = FS.absolutePath(path); @@ -177,11 +177,11 @@ LibraryManager.library = { // Creates a file system record: file, link, device or folder. createObject: function(parent, name, properties, canRead, canWrite) { #if FS_LOG - print('FS.createObject("' + parent + '", ' + - '"' + name + '", ' + - JSON.stringify(properties) + ', ' + - canRead + ', ' + - canWrite + ')'); + Module['print']('FS.createObject("' + parent + '", ' + + '"' + name + '", ' + + JSON.stringify(properties) + ', ' + + canRead + ', ' + + canWrite + ')'); #endif if (!parent) parent = '/'; if (typeof parent === 'string') parent = FS.findObject(parent); @@ -257,11 +257,20 @@ LibraryManager.library = { var properties = {isDevice: false, contents: data}; return FS.createFile(parent, name, properties, canRead, canWrite); }, - // Creates a file record for lazy-loading from a URL. + // Creates a file record for lazy-loading from a URL. XXX This requires a synchronous + // XHR, which is not possible in browsers except in a web worker! Use preloading, + // either --preload-file in emcc or FS.createPreloadedFile createLazyFile: function(parent, name, url, canRead, canWrite) { var properties = {isDevice: false, url: url}; return FS.createFile(parent, name, properties, canRead, canWrite); }, + // Preloads a file asynchronously. You can call this before run, for example in + // preRun. run will be delayed until this file arrives and is set up. + createPreloadedFile: function(parent, name, url, canRead, canWrite) { + Browser.asyncLoad(url, function(data) { + FS.createDataFile(parent, name, data, canRead, canWrite); + }); + }, // Creates a link to a sepcific local path. createLink: function(parent, name, target, canRead, canWrite) { var properties = {isDevice: false, link: target}; @@ -340,6 +349,7 @@ LibraryManager.library = { typeof window.prompt == 'function') { // Browser. result = window.prompt('Input: '); + if (result === null) result = String.fromCharCode(0); // cancel ==> EOF } else if (typeof readline == 'function') { // Command line. result = readline(); @@ -371,8 +381,10 @@ LibraryManager.library = { if (!error.printer) error.printer = Module['print']; if (!error.buffer) error.buffer = []; - // Create the temporary folder. - FS.createFolder('/', 'tmp', true, true); + // Create the temporary folder, if not already created + try { + FS.createFolder('/', 'tmp', true, true); + } catch(e) {} // Create the I/O devices. var devFolder = FS.createFolder('/', 'dev', true, true); @@ -1867,7 +1879,7 @@ LibraryManager.library = { #if CATCH_EXIT_CODE throw new ExitStatus(); -#else +#else throw 'exit(' + status + ') called, at ' + new Error().stack; #endif }, @@ -2217,6 +2229,9 @@ LibraryManager.library = { if (!self.called) { STATICTOP = alignMemoryPage(STATICTOP); // make sure we start out aligned self.called = true; +#if GC_SUPPORT + _sbrk.DYNAMIC_START = STATICTOP; +#endif } var ret = STATICTOP; if (bytes != 0) Runtime.staticAlloc(bytes); @@ -2242,6 +2257,15 @@ LibraryManager.library = { // TODO: Document. _scanString__deps: ['_isFloat'], _scanString: function(format, get, unget, varargs) { + if (!__scanString.whiteSpace) { + __scanString.whiteSpace = {}; + __scanString.whiteSpace[' '.charCodeAt(0)] = 1; + __scanString.whiteSpace['\t'.charCodeAt(0)] = 1; + __scanString.whiteSpace['\n'.charCodeAt(0)] = 1; + __scanString.whiteSpace[' '] = 1; + __scanString.whiteSpace['\t'] = 1; + __scanString.whiteSpace['\n'] = 1; + } // Supports %x, %4x, %d.%d, %s, %f, %lf. // TODO: Support all format specifiers. format = Pointer_stringify(format); @@ -2249,6 +2273,7 @@ LibraryManager.library = { var argsi = 0; var fields = 0; var argIndex = 0; + var next; for (var formatIndex = 0; formatIndex < format.length; formatIndex++) { if (next <= 0) return fields; var next = get(); @@ -2264,11 +2289,14 @@ LibraryManager.library = { if (formatIndex != maxSpecifierStart) { max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10); } - // TODO: Handle type size modifier. var long_ = false; + var half = false; if (format[formatIndex] == 'l') { long_ = true; formatIndex++; + } else if (format[formatIndex] == 'h') { + half = true; + formatIndex++; } var type = format[formatIndex]; formatIndex++; @@ -2288,13 +2316,18 @@ LibraryManager.library = { buffer.pop(); unget(); } + unget(); + next = get(); } else { + var first = true; while ((curr < max_ || isNaN(max_)) && next > 0) { - if ((type === 'd' && next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) || - (type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) || - next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) || - next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0))) || - (type === 's' && (next != ' '.charCodeAt(0) && next != '\t'.charCodeAt(0) && next != '\n'.charCodeAt(0))) && + if (!(next in __scanString.whiteSpace) && // stop on whitespace + (type == 's' || + ((type === 'd' || type == 'u') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) || + (first && next == '-'.charCodeAt(0)))) || + (type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) || + next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) || + next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0)))) && (formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up buffer.push(String.fromCharCode(next)); next = get(); @@ -2302,6 +2335,7 @@ LibraryManager.library = { } else { break; } + first = false; } } if (buffer.length === 0) return 0; // Failure. @@ -2309,8 +2343,12 @@ LibraryManager.library = { var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getNativeFieldSize('void*'); switch (type) { - case 'd': - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}} + case 'd': case 'u': + if (half) { + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}}; + } else { + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}}; + } break; case 'x': {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}} @@ -2330,6 +2368,12 @@ LibraryManager.library = { break; } fields++; + } else if (format[formatIndex] in __scanString.whiteSpace) { + while (next in __scanString.whiteSpace) { + next = get(); + if (next <= 0) return fields; // End of input. + } + unget(); } else { // Not a specifier. if (format[formatIndex].charCodeAt(0) !== next) { @@ -3480,6 +3524,9 @@ LibraryManager.library = { return ret * multiplier; }, + strtod_l: 'strtod', // no locale support yet + strtold: 'strtod', // XXX add real support for long double + strtold_l: 'strtold', // no locale support yet _parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'], _parseInt: function(str, endptr, base, min, max, bits, unsign) { @@ -3956,19 +4003,35 @@ LibraryManager.library = { }, strspn: function(pstr, pset) { - var str = String_copy(pstr, true); - var set = String_copy(pset); - var i = 0; - while (set.indexOf(str[i]) != -1) i++; // Must halt, as 0 is in str but not set - return i; + var str = pstr, set, strcurr, setcurr; + while (1) { + strcurr = {{{ makeGetValue('str', '0', 'i8') }}}; + if (!strcurr) return str - pstr; + set = pset; + while (1) { + setcurr = {{{ makeGetValue('set', '0', 'i8') }}}; + if (!setcurr || setcurr == strcurr) break; + set++; + } + if (!setcurr) return str - pstr; + str++; + } }, strcspn: function(pstr, pset) { - var str = String_copy(pstr, true); - var set = String_copy(pset, true); - var i = 0; - while (set.indexOf(str[i]) == -1) i++; // Must halt, as 0 is in both - return i; + var str = pstr, set, strcurr, setcurr; + while (1) { + strcurr = {{{ makeGetValue('str', '0', 'i8') }}}; + if (!strcurr) return str - pstr; + set = pset; + while (1) { + setcurr = {{{ makeGetValue('set', '0', 'i8') }}}; + if (!setcurr || setcurr == strcurr) break; + set++; + } + if (setcurr) return str - pstr; + str++; + } }, strcpy: function(pdest, psrc) { @@ -4394,6 +4457,21 @@ LibraryManager.library = { */ }, + llvm_bswap_i16: function(x) { + x = unSign(x, 32); + var bytes = []; + bytes[0] = x & 255; + x >>= 8; + bytes[1] = x & 255; + x >>= 8; + var ret = 0; + ret <<= 8; + ret += bytes[0]; + ret <<= 8; + ret += bytes[1]; + return ret; + }, + llvm_bswap_i32: function(x) { x = unSign(x, 32); var bytes = []; @@ -4408,7 +4486,7 @@ LibraryManager.library = { } return ret; }, - + llvm_ctlz_i32: function(x) { for (var i=0; i<32; i++) { if ( (x & (1 << (31-i))) != 0 ) { @@ -4672,6 +4750,24 @@ LibraryManager.library = { }; }, + llvm_uadd_with_overflow_i64__deps: [function() { preciseI64MathUsed = 1 }], + llvm_uadd_with_overflow_i64: function(xl, xh, yl, yh) { + i64Math.add(xl, xh, yl, yh); + return { + f0: i64Math.result, + f1: 0 // XXX Need to hack support for this in long.js + }; + }, + + llvm_umul_with_overflow_i64__deps: [function() { preciseI64MathUsed = 1 }], + llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) { + i64Math.mul(xl, xh, yl, yh); + return { + f0: i64Math.result, + f1: 0 // XXX Need to hack support for this in long.js + }; + }, + llvm_stacksave: function() { var self = _llvm_stacksave; if (!self.LLVM_SAVEDSTACKS) { @@ -4711,6 +4807,11 @@ LibraryManager.library = { llvm_lifetime_ |