diff options
35 files changed, 2784 insertions, 570 deletions
@@ -47,6 +47,7 @@ a license to everyone to use it as detailed in LICENSE.) * Michael Riss <Michael.Riss@gmx.de> * Jasper St. Pierre <jstpierre@mecheye.net> * Manuel Schölling <manuel.schoelling@gmx.de> +* Bruce Mitchener, Jr. <bruce.mitchener@gmail.com> @@ -90,8 +90,6 @@ LLVM_OPT_LEVEL = { 3: 3, } -MEMCPY_ALIASES = ['memcpy', 'llvm.memcpy.i32', 'llvm.memcpy.i64', 'llvm.memcpy.p0i8.p0i8.i32', 'llvm.memcpy.p0i8.p0i8.i64'] - DEBUG = int(os.environ.get('EMCC_DEBUG') or 0) TEMP_DIR = os.environ.get('EMCC_TEMP_DIR') LEAVE_INPUTS_RAW = os.environ.get('EMCC_LEAVE_INPUTS_RAW') # Do not compile .ll files into .bc, just compile them with emscripten directly @@ -248,6 +246,15 @@ Options that are modified or new in %s include: are compiling to. To run your code, you will need both the .html and the .data. + emcc runs tools/file_packager.py to do the + actual packaging of embedded and preloaded + files. You can run the file packager yourself + if you want, see docs inside that file. You + should then put the output of the file packager + in an emcc --pre-js, so that it executes before + your main compiled code (or run it before in + some other way). + --compression <codec> Compress both the compiled code and embedded/ preloaded files. <codec> should be a triple, @@ -596,6 +603,10 @@ try: keep_debug = False bind = False jcache = False + if use_cxx: + default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. + else: + default_cxx_std = '' # Compiling C code with .c files, don't enforce a default C++ std. def check_bad_eq(arg): assert '=' not in arg, 'Invalid parameter (do not use "=" with "--" options)' @@ -659,7 +670,11 @@ try: keep_debug = True elif newargs[i] == '--bind': bind = True - newargs[i] = '-std=c++11' # Force C++11 for embind code + newargs[i] = '' + if default_cxx_std: + default_cxx_std = '-std=c++11' # Force C++11 for embind code, but only if user has not explicitly overridden a standard. + elif newargs[i].startswith('-std='): + default_cxx_std = '' # User specified a standard to use, clear Emscripten from specifying it. elif newargs[i].startswith('--embed-file'): check_bad_eq(newargs[i]) embed_files.append(newargs[i+1]) @@ -717,6 +732,10 @@ try: absolute_warning_shown = True newargs = [ arg for arg in newargs if arg is not '' ] + # If user did not specify a default -std for C++ code, specify the emscripten default. + if default_cxx_std: + newargs = newargs + [default_cxx_std] + if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] if llvm_lto is None: llvm_lto = llvm_opts > 0 if closure is None: closure = 1 if opt_level >= 2 else 0 @@ -940,7 +959,7 @@ try: def create_libc(): if DEBUG: print >> sys.stderr, 'emcc: building libc for cache' o_s = [] - for src in ['dlmalloc.c', os.path.join('libc', 'musl', 'memcpy.c'), os.path.join('libcxx', 'new.cpp')]: + for src in ['dlmalloc.c', os.path.join('libcxx', 'new.cpp')]: o = in_temp(os.path.basename(src) + '.o') execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o], stdout=stdout, stderr=stderr) o_s.append(o) @@ -948,13 +967,6 @@ try: return in_temp('libc.bc') def fix_libc(need): - # If an intrinsic alias of memcpy is used, we need memcpy - for memcpy_alias in MEMCPY_ALIASES: - if memcpy_alias in need: - if '_memcpy' not in shared.Settings.EXPORTED_FUNCTIONS: - shared.Settings.EXPORTED_FUNCTIONS.append('_memcpy') - break - # libc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines try: if shared.Settings.CORRECT_SIGNS == 0: raise Exception('we need to change to 2') @@ -1195,7 +1207,7 @@ try: js_optimizer_queue += [get_eliminate(), 'simplifyExpressionsPre'] - if shared.Settings.RELOOP: + if shared.Settings.RELOOP and not shared.Settings.ASM_JS: js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches if closure: diff --git a/emscripten.py b/emscripten.py index 2ceb5e13..af762a21 100755 --- a/emscripten.py +++ b/emscripten.py @@ -321,12 +321,14 @@ def emscript(infile, settings, outfile, libraries=[]): infos = [make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()] function_tables_defs = '\n'.join([info[0] for info in infos] + [info[1] for info in infos]) + asm_setup = '' maths = ['Math.' + func for func in ['floor', 'abs', 'sqrt', 'pow', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'atan2', 'exp', 'log', 'ceil']] if settings['USE_MATH_IMUL']: maths += ['Math.imul'] + asm_setup += 'if (!Math.imul) Math.imul = function(x, y) { return (x*y)|0 }; // # not a real polyfill since semantics not identical, but close and fairly fast\n' fundamentals = ['Math', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] math_envs = ['Runtime.bitshift64', 'Math.min'] # TODO: move min to maths - asm_setup = '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs]) + asm_setup += '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs]) basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat', 'copyTempDouble', 'copyTempFloat'] + [m.replace('.', '_') for m in math_envs] if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] diff --git a/src/library.js b/src/library.js index 5071552a..623d1626 100644 --- a/src/library.js +++ b/src/library.js @@ -252,7 +252,7 @@ LibraryManager.library = { var properties = {isFolder: true, isDevice: false, contents: {}}; return FS.createObject(parent, name, properties, canRead, canWrite); }, - // Creates a a folder and all its missing parents. + // Creates a folder and all its missing parents. createPath: function(parent, path, canRead, canWrite) { var current = FS.findObject(parent); if (current === null) throw new Error('Invalid parent.'); @@ -414,7 +414,7 @@ LibraryManager.library = { processData(url); } }, - // Creates a link to a sepcific local path. + // Creates a link to a specific local path. createLink: function(parent, name, target, canRead, canWrite) { var properties = {isDevice: false, link: target}; return FS.createFile(parent, name, properties, canRead, canWrite); @@ -1120,7 +1120,7 @@ LibraryManager.library = { open: function(path, oflag, varargs) { // int open(const char *path, int oflag, ...); // http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html - // NOTE: This implementation tries to mimic glibc rather that strictly + // NOTE: This implementation tries to mimic glibc rather than strictly // following the POSIX standard. var mode = {{{ makeGetValue('varargs', 0, 'i32') }}}; @@ -1341,7 +1341,7 @@ LibraryManager.library = { poll: function(fds, nfds, timeout) { // int poll(struct pollfd fds[], nfds_t nfds, int timeout); // http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html - // NOTE: This is pretty much a no-op mimicing glibc. + // NOTE: This is pretty much a no-op mimicking glibc. var offsets = ___pollfd_struct_layout; var nonzero = 0; for (var i = 0; i < nfds; i++) { @@ -1505,7 +1505,7 @@ LibraryManager.library = { // long fpathconf(int fildes, int name); // http://pubs.opengroup.org/onlinepubs/000095399/functions/encrypt.html // NOTE: The first parameter is ignored, so pathconf == fpathconf. - // The constants here aren't real values. Just mimicing glibc. + // The constants here aren't real values. Just mimicking glibc. switch (name) { case {{{ cDefine('_PC_LINK_MAX') }}}: return 32000; @@ -4221,8 +4221,11 @@ LibraryManager.library = { memcpy__sig: 'iiii', memcpy: function (dest, src, num) { dest = dest|0; src = src|0; num = num|0; + var ret = 0; + ret = dest|0; if ((dest&3) == (src&3)) { - while (dest & 3 & num) { + while (dest & 3) { + if ((num|0) == 0) return ret|0; {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}}; dest = (dest+1)|0; src = (src+1)|0; @@ -4241,7 +4244,7 @@ LibraryManager.library = { src = (src+1)|0; num = (num-1)|0; } - return dest|0; + return ret|0; }, wmemcpy: function() { throw 'wmemcpy not implemented' }, diff --git a/src/library_gc.js b/src/library_gc.js index fe4cbf63..083019ca 100644 --- a/src/library_gc.js +++ b/src/library_gc.js @@ -1,14 +1,16 @@ if (GC_SUPPORT) { EXPORTED_FUNCTIONS['_calloc'] = 1; + EXPORTED_FUNCTIONS['_realloc'] = 1; var LibraryGC = { - $GC__deps: ['sbrk'], + $GC__deps: ['sbrk', 'realloc'], $GC: { ALLOCATIONS_TO_GC: 1*1024*1024, sizes: {}, // if in this map, then a live allocated object. this is iterable scannables: {}, + uncollectables: {}, finalizers: {}, finalizerArgs: {}, @@ -34,7 +36,7 @@ if (GC_SUPPORT) { } }, - malloc: function(bytes, clear, scannable) { + malloc: function(bytes, clear, scannable, collectable) { if (!bytes) return 0; var ptr; if (clear) { @@ -42,6 +44,9 @@ if (GC_SUPPORT) { } else { ptr = _malloc(bytes); } + if (!collectable) { + GC.uncollectables[ptr] = true; + } GC.scannables[ptr] = scannable; GC.sizes[ptr] = bytes; GC.totalAllocations += bytes; @@ -49,6 +54,41 @@ if (GC_SUPPORT) { return ptr; }, + realloc: function(ptr, newBytes) { + if (newBytes != 0) { + var oldBytes = GC.sizes[ptr]; + var newPtr = _realloc(ptr, newBytes); + if (newBytes > oldBytes) { + _memset(newPtr + oldBytes, 0, newBytes - oldBytes); + } + delete GC.sizes[ptr]; + GC.sizes[newPtr] = newBytes; + scannable = GC.scannables[ptr]; + delete GC.scannables[ptr]; + GC.scannables[newPtr] = scannable; + var finalizer = GC.finalizers[ptr]; + if (finalizer) { + delete GC.finalizers[ptr]; + GC.finalizers[newPtr] = finalizer; + } + var finalizerArgs = GC.finalizerArgs[ptr]; + if (finalizerArgs) { + delete GC.finalizerArgs[ptr]; + GC.finalizerArgs[newPtr] = finalizerArgs; + } + var uncollectable = GC.uncollectables[ptr]; + if (uncollectable) { + delete GC.uncollectables[ptr]; + GC.uncollectables[newPtr] = true; + } + GC.totalAllocations += (newBytes - oldBytes); + return newPtr; + } else { + GC.free(ptr); + return 0; + } + }, + free: function(ptr) { // does not check if anything refers to it, this is a forced free var finalizer = GC.finalizers[ptr]; if (finalizer) { @@ -56,8 +96,8 @@ if (GC_SUPPORT) { GC.finalizers[ptr] = 0; } _free(ptr); - delete GC.sizes[ptr]; GC.totalAllocations -= GC.sizes[ptr]; + delete GC.sizes[ptr]; }, registerFinalizer: function(ptr, func, arg, oldFunc, oldArg) { @@ -74,6 +114,10 @@ if (GC_SUPPORT) { GC.finalizerArgs[ptr] = arg; }, + getHeapSize: function() { + return GC.totalAllocations; + }, + maybeCollect: function() { if (GC.needCollect()) GC.collect(); }, @@ -123,7 +167,7 @@ if (GC_SUPPORT) { sweep: function() { // traverse all objects and free all unreachable var freeList = []; for (var ptr in GC.sizes) { - if (!GC.reachable[ptr]) { + if (!GC.reachable[ptr] && !GC.uncollectables[ptr]) { freeList.push(parseInt(ptr)); } } @@ -140,12 +184,22 @@ if (GC_SUPPORT) { GC_MALLOC__deps: ['$GC'], GC_MALLOC: function(bytes) { - return GC.malloc(bytes, true, true); + return GC.malloc(bytes, true, true, true); }, GC_MALLOC_ATOMIC__deps: ['$GC'], GC_MALLOC_ATOMIC: function(bytes) { - return GC.malloc(bytes, false, false); + return GC.malloc(bytes, false, false, true); + }, + + GC_MALLOC_UNCOLLECTABLE__deps: ['$GC'], + GC_MALLOC_UNCOLLECTABLE: function(bytes) { + return GC.malloc(bytes, true, true, false); + }, + + GC_REALLOC__deps: ['$GC'], + GC_REALLOC: function(ptr, newBytes) { + return GC.realloc(ptr, newBytes); }, GC_FREE__deps: ['$GC'], @@ -158,6 +212,11 @@ if (GC_SUPPORT) { GC.registerFinalizer(ptr, func, arg, old_func, old_arg); }, + GC_get_heap_size__deps: ['$GC'], + GC_get_heap_size: function() { + return GC.getHeapSize(); + }, + GC_MAYBE_COLLECT__deps: ['$GC'], GC_MAYBE_COLLECT: function() { GC.maybeCollect(); diff --git a/src/library_jansson.js b/src/library_jansson.js index 368584a7..93f239fc 100644 --- a/src/library_jansson.js +++ b/src/library_jansson.js @@ -74,7 +74,7 @@ var LibraryJansson = { _free(node['stringValuePtr']); }, - // Loads a string into the Javascript JSNON context + // Loads a string into the Javascript JSON context // Only the root node is loaded. Child nodes are loaded on demand via `loadChildNodes` method. load: function(string, flags, error) { // This is potentially a security problem. diff --git a/src/parseTools.js b/src/parseTools.js index f5e2f33f..e081d0de 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -111,7 +111,7 @@ function isStructPointerType(type) { // |%5()| as a function call (like |i32 (i8*)| etc.). So // we must check later on, in call(), where we have more // context, to differentiate such cases. - // A similar thing happns in isStructType() + // A similar thing happens in isStructType() return !Runtime.isNumberType(type) && type[0] == '%'; } @@ -1045,9 +1045,14 @@ function asmCoercion(value, type, signedness) { } } +var TWO_TWENTY = Math.pow(2, 20); + function asmMultiplyI32(a, b) { // special-case: there is no integer multiply in asm, because there is no true integer // multiply in JS. While we wait for Math.imul, do double multiply + if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY)) { + return '(((' + a + ')*(' + b + '))&-1)'; // small enough to emit directly as a multiply + } if (USE_MATH_IMUL) { return 'Math.imul(' + a + ',' + b + ')'; } @@ -1949,6 +1954,7 @@ function processMathop(item) { if (item.type[0] === 'i') { bits = parseInt(item.type.substr(1)); } + var bitsBefore = parseInt((item.params[0] ? item.params[0].type : item.type).substr(1)); // remove i to leave the number of bits left after this var bitsLeft = parseInt(((item.params[1] && item.params[1].ident) ? item.params[1].ident : item.type).substr(1)); // remove i to leave the number of bits left after this operation function integerizeBignum(value) { @@ -2230,7 +2236,14 @@ function processMathop(item) { } // Note that zext has sign checking, see above. We must guard against -33 in i8 turning into -33 in i32 // then unsigning that i32... which would give something huge. - case 'zext': case 'fpext': case 'sext': return idents[0]; + case 'zext': { + if (EXPLICIT_ZEXT && bitsBefore == 1 && bitsLeft > 1) { + return '(' + originalIdents[0] + '?1:0)'; // explicit bool-to-int conversion, work around v8 issue 2513 + break; + } + // otherwise, fall through + } + case 'fpext': case 'sext': return idents[0]; case 'fptrunc': return idents[0]; case 'select': return idents[0] + ' ? ' + asmEnsureFloat(idents[1], item.type) + ' : ' + asmEnsureFloat(idents[2], item.type); case 'ptrtoint': case 'inttoptr': { diff --git a/src/relooper/test.txt b/src/relooper/test.txt index b7c8794d..12d0ef39 100644 --- a/src/relooper/test.txt +++ b/src/relooper/test.txt @@ -54,7 +54,7 @@ while(1) { // code 2 if (!($2)) { var $x_1 = $x_0; - label = 19; + label = 18; break; } // code 3 @@ -64,7 +64,7 @@ while(1) { var $i_0 = $7;var $x_0 = $5; } } -if (label == 19) { +if (label == 18) { // code 7 } // code 4 diff --git a/src/relooper/test2.txt b/src/relooper/test2.txt index c77ce491..a847e806 100644 --- a/src/relooper/test2.txt +++ b/src/relooper/test2.txt @@ -1,12 +1,11 @@ ep -do { - if (ep -> LBB1) { - LBB1 - if (!(LBB1 -> LBB2)) { - break; - } - LBB2 +L1: +if (ep -> LBB1) { + LBB1 + if (!(LBB1 -> LBB2)) { + break L1; } -} while(0); + LBB2 +} LBB3 diff --git a/src/relooper/test3.txt b/src/relooper/test3.txt index 696542ef..7d06f06a 100644 --- a/src/relooper/test3.txt +++ b/src/relooper/test3.txt @@ -1,27 +1,25 @@ ep -do { - if (ep -> LBB1) { - LBB1 - if (!(LBB1 -> LBB2)) { - break; - } - LBB2 +L1: +if (ep -> LBB1) { + LBB1 + if (!(LBB1 -> LBB2)) { + break L1; } -} while(0); + LBB2 +} LBB3 -L5: do { - if (LBB3 -> LBB4) { - LBB4 - if (!(LBB4 -> LBB5)) { - break; - } - while(1) { - LBB5 - if (LBB5 -> LBB6) { - break L5; - } +L5: +if (LBB3 -> LBB4) { + LBB4 + if (!(LBB4 -> LBB5)) { + break L5; + } + while(1) { + LBB5 + if (LBB5 -> LBB6) { + break L5; } } -} while(0); +} LBB6 diff --git a/src/relooper/test4.txt b/src/relooper/test4.txt index f0bfb972..2ab3265a 100644 --- a/src/relooper/test4.txt +++ b/src/relooper/test4.txt @@ -1,17 +1,16 @@ //19 -do { - if ( 1 ) { - //20 - if (!( 1 )) { - label = 4; - break; - } - //21 - break; - } else { +L1: +if ( 1 ) { + //20 + if (!( 1 )) { label = 4; + break L1; } -} while(0); + //21 + break L1; +} else { + label = 4; +} if (label == 4) { //22 } diff --git a/src/relooper/test6.txt b/src/relooper/test6.txt index c5effd08..0ec7e666 100644 --- a/src/relooper/test6.txt +++ b/src/relooper/test6.txt @@ -1,12 +1,11 @@ //0 -do { - if (check(0)) { - //1 - if (!(check(1))) { - break; - } - //2 +L1: +if (check(0)) { + //1 + if (!(check(1))) { + break L1; } -} while(0); + //2 +} //3 diff --git a/src/relooper/test_debug.txt b/src/relooper/test_debug.txt index 1c7d0508..02377fb7 100644 --- a/src/relooper/test_debug.txt +++ b/src/relooper/test_debug.txt @@ -83,14 +83,13 @@ int main() { // === Optimizing shapes === // Fusing Multiple to Simple ep -do { - if (ep -> LBB1) { - LBB1 - if (!(LBB1 -> LBB2)) { - break; - } - LBB2 +L1: +if (ep -> LBB1) { + LBB1 + if (!(LBB1 -> LBB2)) { + break L1; } -} while(0); + LBB2 +} LBB3 diff --git a/src/relooper/test_fuzz1.txt b/src/relooper/test_fuzz1.txt index 5122257e..09edb594 100644 --- a/src/relooper/test_fuzz1.txt +++ b/src/relooper/test_fuzz1.txt @@ -3,13 +3,12 @@ print('entry'); var label; var state; var decisions = [4, 1, 7, 2, 6, 6, 8]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } print(5); state = check(); print(6); state = check(); -do { - if (state == 7) { - print(7); state = check(); - label = 3; - break; - } -} while(0); +L3: +if (state == 7) { + print(7); state = check(); + label = 3; + break L3; +} L5: while(1) { if (label == 3) { label = 0; diff --git a/src/relooper/test_fuzz5.txt b/src/relooper/test_fuzz5.txt index 9548205c..7c795d53 100644 --- a/src/relooper/test_fuzz5.txt +++ b/src/relooper/test_fuzz5.txt @@ -3,22 +3,21 @@ print('entry'); var label; var state; var decisions = [133, 98, 134, 143, 162, 187, 130, 87, 91, 49, 102, 47, 9, 132, 179, 176, 157, 25, 64, 161, 57, 107, 16, 167, 185, 45, 191, 180, 23, 131]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } L1: while(1) { print(7); state = check(); - do { - if (state % 3 == 1) { - label = 3; - } else if (state % 3 == 0) { - print(8); state = check(); - if (state % 2 == 0) { - label = 5; - break; - } else { - label = 7; - break; - } + L3: + if (state % 3 == 1) { + label = 3; + } else if (state % 3 == 0) { + print(8); state = check(); + if (state % 2 == 0) { + label = 5; + break L3; } else { - break L1; + label = 7; + break L3; } - } while(0); + } else { + break L1; + } while(1) { if (label == 3) { label = 0; diff --git a/src/relooper/test_inf.txt b/src/relooper/test_inf.txt index 379d2083..3e292433 100644 --- a/src/relooper/test_inf.txt +++ b/src/relooper/test_inf.txt @@ -5,35 +5,34 @@ if (uint(i4) >= uint(i5)) { code 1 } code 3 -L5: do { - if (!(i2 == 0)) { - code 4 - while(1) { - code 5 - if (uint(i6) >= uint(i7)) { - code 7 - } else { - code 6 - } - code 8 - if (uint(i6) >= uint(i7)) { - code 10 - } else { - code 9 - } - code 11 - if (uint(i5) >= uint(i6)) { - code 13 - } else { - code 12 - } - code 14 - if (!(i2 != 0)) { - break L5; - } +L5: +if (!(i2 == 0)) { + code 4 + while(1) { + code 5 + if (uint(i6) >= uint(i7)) { + code 7 + } else { + code 6 + } + code 8 + if (uint(i6) >= uint(i7)) { + code 10 + } else { + code 9 + } + code 11 + if (uint(i5) >= uint(i6)) { + code 13 + } else { + code 12 + } + code 14 + if (!(i2 != 0)) { + break L5; } } -} while(0); +} code 15 if (uint(i4) >= uint(i5)) { code 17 @@ -41,179 +40,178 @@ if (uint(i4) >= uint(i5)) { code 16 } code 18 -L26: do { - if (!(i2 == 0)) { - code 19 - while(1) { - code 20 - if (uint(i5) >= uint(i6)) { - code 22 - } else { - code 21 - } - code 23 - if (uint(i5) >= uint(i6)) { - code 25 - } else { - code 24 - } - code 26 - if (uint(i5) >= uint(i6)) { - code 28 - } else { - code 27 - } - code 29 - if (uint(i5) >= uint(i6)) { - code 31 - } else { - code 30 - } - code 32 - if (uint(i5) >= uint(i6)) { - code 34 - } else { - code 33 - } - code 35 - if (uint(i5) >= uint(i6)) { - code 37 - } else { - code 36 - } - code 38 - if (uint(i5) >= uint(i6)) { - code 40 - } else { - code 39 - } - code 41 - if (uint(i5) >= uint(i6)) { - code 43 - } else { - code 42 - } - code 44 - if (uint(i5) >= uint(i6)) { |