diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index a4b9c585e..9c119c752 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -39,7 +39,14 @@ vAPI.cantWebsocket = browser.webRequest.ResourceType instanceof Object === false || browser.webRequest.ResourceType.WEBSOCKET !== 'websocket'; +vAPI.canWASM = vAPI.webextFlavor.soup.has('chromium') === false; +if ( vAPI.canWASM === false ) { + const csp = manifest.content_security_policy; + vAPI.canWASM = csp !== undefined && csp.indexOf("'wasm-eval'") !== -1; +} + vAPI.supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet'); + // The real actual webextFlavor value may not be set in stone, so listen // for possible future changes. window.addEventListener('webextFlavor', function() { diff --git a/src/js/background.js b/src/js/background.js index 46d1d6f9d..a63a598f6 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -142,7 +142,7 @@ const µBlock = (( ) => { // jshint ignore:line // Read-only systemSettings: { compiledMagic: 23, // Increase when compiled format changes - selfieMagic: 24, // Increase when selfie format changes + selfieMagic: 25, // Increase when selfie format changes }, // https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501 diff --git a/src/js/hntrie.js b/src/js/hntrie.js index ad70becb7..22f917300 100644 --- a/src/js/hntrie.js +++ b/src/js/hntrie.js @@ -710,12 +710,7 @@ HNTrieContainer.prototype.HNTrieRef.prototype.needle = ''; // Soft-dependency on vAPI so that the code here can be used outside of // uBO (i.e. tests, benchmarks) - if ( - typeof vAPI === 'object' && - vAPI.webextFlavor.soup.has('firefox') === false - ) { - return; - } + if ( typeof vAPI === 'object' && vAPI.canWASM !== true ) { return; } // Soft-dependency on µBlock's advanced settings so that the code here can // be used outside of uBO (i.e. tests, benchmarks) diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index 4c339a86e..0ab80f246 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -1518,26 +1518,25 @@ const FilterDataHolderResult = class { /******************************************************************************/ const FilterCollection = class { - constructor(i = 0, n = 0) { + constructor(i = 0) { this.i = i | 0; - this.n = n | 0; } get size() { - return this.n; + let n = 0; + this.forEach(( ) => { n += 1; }); + return n; } unshift(iunit) { const j = this.i; this.i = filterSequenceAdd(iunit, j); - this.n += 1; } shift() { const sequences = filterSequences; filterUnits[sequences[this.i+0]] = null; this.i = sequences[this.i+1]; - this.n -= 1; } forEach(fn) { @@ -1553,7 +1552,7 @@ const FilterCollection = class { } toSelfie() { - return [ this.fid, this.i, this.n ]; + return [ this.fid, this.i ]; } static compile(ctor, fdata) { @@ -1577,7 +1576,7 @@ const FilterCollection = class { } static fromSelfie(ctor, args) { - return new ctor(args[1], args[2]); + return new ctor(args[1]); } }; @@ -1585,14 +1584,13 @@ const FilterCollection = class { const FilterComposite = class extends FilterCollection { match() { - let i = this.i; - if ( i === 0 ) { return false; } const sequences = filterSequences; const units = filterUnits; - do { + let i = this.i; + while ( i !== 0 ) { if ( units[sequences[i+0]].match() !== true ) { return false; } i = sequences[i+1]; - } while ( i !== 0 ); + } return true; } @@ -1868,18 +1866,17 @@ const FilterBucket = class extends FilterCollection { return true; } } - let i = this.i; - if ( i === 0 ) { return false; } const sequences = filterSequences; const units = filterUnits; - do { + let i = this.i; + while ( i !== 0 ) { if ( units[sequences[i+0]].match() ) { this.$matchedTrie = false; this.$matchedUnit = sequences[i+0]; return true; } i = sequences[i+1]; - } while ( i !== 0 ); + } return false; } @@ -1910,19 +1907,14 @@ const FilterBucket = class extends FilterCollection { } optimize() { - if ( this.n < 3 ) { return; } const units = filterUnits; - const trieables = new Set(); + let n = 0; let i = this.i; - for (;;) { - const f = units[filterSequences[i+0]]; - if ( f.isBidiTrieable === true ) { - trieables.add(i); - } + do { + if ( units[filterSequences[i+0]].isBidiTrieable ) { n += 1; } i = filterSequences[i+1]; - if ( i === 0 ) { break; } - } - if ( trieables.size < 3 ) { return; } + } while ( i !== 0 && n < 3 ); + if ( n < 3 ) { return; } if ( this.plainTrie === null ) { this.plainTrie = bidiTrie.createOne(); } @@ -1931,7 +1923,7 @@ const FilterBucket = class extends FilterCollection { for (;;) { const iunit = filterSequences[i+0]; const inext = filterSequences[i+1]; - if ( trieables.has(i) ) { + if ( units[iunit].isBidiTrieable ) { this._addToTrie(iunit); if ( iprev !== 0 ) { filterSequences[iprev+1] = inext; @@ -1982,8 +1974,8 @@ const FilterBucket = class extends FilterCollection { static fromSelfie(args) { const bucket = FilterCollection.fromSelfie(FilterBucket, args); - if ( args.length > 3 && Array.isArray(args[3]) ) { - bucket.plainTrie = bidiTrie.createOne(args[3]); + if ( args.length > 2 && Array.isArray(args[2]) ) { + bucket.plainTrie = bidiTrie.createOne(args[2]); } return bucket; } @@ -2688,6 +2680,8 @@ FilterContainer.prototype.freeze = function() { const unserialize = µb.CompiledLineIO.unserialize; const units = filterUnits; + const t0 = Date.now(); + for ( const line of this.goodFilters ) { if ( this.badFilters.has(line) ) { this.discardedCount += 1; @@ -2791,6 +2785,8 @@ FilterContainer.prototype.freeze = function() { FilterHostnameDict.optimize(); bidiTrieOptimize(); this.frozen = true; + + log.info(`staticNetFilteringEngine.freeze() took ${Date.now()-t0} ms`); }; /******************************************************************************/ diff --git a/src/js/storage.js b/src/js/storage.js index 084ca98f4..6718573a0 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -621,7 +621,11 @@ const loadedListKeys = []; let loadingPromise; + const t0 = Date.now(); + const onDone = function() { + log.info(`loadFilterLists() took ${Date.now()-t0} ms`); + this.staticNetFilteringEngine.freeze(); this.staticExtFilteringEngine.freeze(); this.redirectEngine.freeze(); @@ -696,9 +700,9 @@ if ( loadingPromise instanceof Promise === false ) { loadedListKeys.length = 0; loadingPromise = Promise.all([ - this.getAvailableLists().then(lists => { - return onFilterListsReady.call(this, lists); - }), + this.getAvailableLists().then(lists => + onFilterListsReady.call(this, lists) + ), this.loadRedirectResources(), ]).then(( ) => { onDone.call(this); diff --git a/src/js/strie.js b/src/js/strie.js index 8b5c16fab..896a66144 100644 --- a/src/js/strie.js +++ b/src/js/strie.js @@ -174,40 +174,40 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1); const buf8 = this.buf8; const char0 = buf32[CHAR0_SLOT]; const aR = buf32[HAYSTACK_SIZE_SLOT]; - let al = ai; - let c, v, bl, n; + let al = ai, x = 0, y = 0; for (;;) { - c = buf8[al]; + x = buf8[al]; al += 1; - // find first segment with a first-character match + // find matching segment for (;;) { - v = buf32[icell+SEGMENT_INFO]; - bl = char0 + (v & 0x00FFFFFF); - if ( buf8[bl] === c ) { break; } + y = buf32[icell+SEGMENT_INFO]; + let bl = char0 + (y & 0x00FFFFFF); + if ( buf8[bl] === x ) { + y = (y >>> 24) - 1; + if ( y !== 0 ) { + x = al + y; + if ( x > aR ) { return 0; } + for (;;) { + bl += 1; + if ( buf8[bl] !== buf8[al] ) { return 0; } + al += 1; + if ( al === x ) { break; } + } + } + break; + } icell = buf32[icell+CELL_OR]; if ( icell === 0 ) { return 0; } } - // all characters in segment must match - n = (v >>> 24) - 1; - if ( n !== 0 ) { - const ar = al + n; - if ( ar > aR ) { return 0; } - let i = al, j = bl + 1; - do { - if ( buf8[i] !== buf8[j] ) { return 0; } - j += 1; i += 1; - } while ( i !== ar ); - al = i; - } // next segment icell = buf32[icell+CELL_AND]; - v = buf32[icell+BCELL_EXTRA]; - if ( v <= BCELL_EXTRA_MAX ) { - if ( v !== 0 && this.matchesExtra(ai, al, v) !== 0 ) { + x = buf32[icell+BCELL_EXTRA]; + if ( x <= BCELL_EXTRA_MAX ) { + if ( x !== 0 && this.matchesExtra(ai, al, x) !== 0 ) { return 1; } - let inext = buf32[icell+BCELL_ALT_AND]; - if ( inext !== 0 && this.matchesLeft(inext, ai, al) !== 0 ) { + x = buf32[icell+BCELL_ALT_AND]; + if ( x !== 0 && this.matchesLeft(x, ai, al) !== 0 ) { return 1; } icell = buf32[icell+BCELL_NEXT_AND]; @@ -218,41 +218,41 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1); return 0; } - matchesLeft(iroot, ar, r) { + matchesLeft(icell, ar, r) { const buf32 = this.buf32; const buf8 = this.buf8; const char0 = buf32[CHAR0_SLOT]; - let icell = iroot; - let c, v, br, n; + let x = 0, y = 0; for (;;) { if ( ar === 0 ) { return 0; } ar -= 1; - c = buf8[ar]; + x = buf8[ar]; // find first segment with a first-character match for (;;) { - v = buf32[icell+SEGMENT_INFO]; - n = (v >>> 24) - 1; - br = char0 + (v & 0x00FFFFFF) + n; - if ( buf8[br] === c ) { break; } + y = buf32[icell+SEGMENT_INFO]; + let br = char0 + (y & 0x00FFFFFF); + y = (y >>> 24) - 1; + br += y; + if ( buf8[br] === x ) { // all characters in segment must match + if ( y !== 0 ) { + x = ar - y; + if ( x < 0 ) { return 0; } + for (;;) { + ar -= 1; br -= 1; + if ( buf8[ar] !== buf8[br] ) { return 0; } + if ( ar === x ) { break; } + } + } + break; + } icell = buf32[icell+CELL_OR]; if ( icell === 0 ) { return 0; } } - // all characters in segment must match - if ( n !== 0 ) { - const al = ar - n; - if ( al < 0 ) { return 0; } - let i = ar, j = br; - do { - i -= 1; j -= 1; - if ( buf8[i] !== buf8[j] ) { return 0; } - } while ( i !== al ); - ar = i; - } // next segment icell = buf32[icell+CELL_AND]; - v = buf32[icell+BCELL_EXTRA]; - if ( v <= BCELL_EXTRA_MAX ) { - if ( v !== 0 && this.matchesExtra(ar, r, v) !== 0 ) { + x = buf32[icell+BCELL_EXTRA]; + if ( x <= BCELL_EXTRA_MAX ) { + if ( x !== 0 && this.matchesExtra(ar, r, x) !== 0 ) { return 1; } icell = buf32[icell+BCELL_NEXT_AND]; @@ -263,16 +263,16 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1); } matchesExtra(l, r, ix) { - let iu; + let iu = 0; if ( ix !== 1 ) { iu = this.extraHandler(l, r, ix); if ( iu === 0 ) { return 0; } } else { iu = -1; } + this.buf32[RESULT_IU_SLOT] = iu; this.buf32[RESULT_L_SLOT] = l; this.buf32[RESULT_R_SLOT] = r; - this.buf32[RESULT_IU_SLOT] = iu; return 1; } @@ -926,12 +926,7 @@ const getWasmModule = (( ) => { // Soft-dependency on vAPI so that the code here can be used outside of // uBO (i.e. tests, benchmarks) - if ( - typeof vAPI === 'object' && - vAPI.webextFlavor.soup.has('firefox') === false - ) { - return; - } + if ( typeof vAPI === 'object' && vAPI.canWASM !== true ) { return; } // The wasm module will work only if CPU is natively little-endian, // as we use native uint32 array in our js code. diff --git a/src/js/utils.js b/src/js/utils.js index 6f3fbc62a..c5ae34821 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -149,7 +149,7 @@ _tokenize(encodeInto) { const tokens = this._tokens; let url = this._urlOut; - let l = url.length; + let l = url.length | 0; if ( l === 0 ) { return 0; } if ( l > 2048 ) { url = url.slice(0, 2048); @@ -163,7 +163,7 @@ for (;;) { for (;;) { if ( i === l ) { return j; } - c = url.charCodeAt(i); + c = url.charCodeAt(i) | 0; charCodes[i] = c; v = vtc[c]; i += 1; @@ -172,7 +172,7 @@ th = v; ti = i - 1; n = 1; for (;;) { if ( i === l ) { break; } - c = url.charCodeAt(i); + c = url.charCodeAt(i) | 0; charCodes[i] = c; v = vtc[c]; i += 1; diff --git a/src/js/wasm/biditrie.wasm b/src/js/wasm/biditrie.wasm index df0666008..d9066ae2b 100644 Binary files a/src/js/wasm/biditrie.wasm and b/src/js/wasm/biditrie.wasm differ diff --git a/src/js/wasm/biditrie.wat b/src/js/wasm/biditrie.wat index 551f58f6b..9e1df88e0 100644 --- a/src/js/wasm/biditrie.wat +++ b/src/js/wasm/biditrie.wat @@ -60,14 +60,9 @@ (local $char0 i32) (local $aR i32) (local $al i32) - (local $c i32) - (local $v i32) (local $bl i32) - (local $n i32) - (local $ar i32) - (local $i i32) - (local $j i32) - (local $inext i32) + (local $x i32) + (local $y i32) ;; trie index is a uint32 offset, need to convert to uint8 offset get_local $icell i32.const 2 @@ -90,33 +85,78 @@ block $matchNotFound ;; for (;;) { loop $mainLoop - ;; c = buf8[al]; + ;; x = buf8[al]; get_local $al i32.load8_u - set_local $c + set_local $x ;; al += 1; get_local $al i32.const 1 i32.add set_local $al - ;; // find first segment with a first-character match + ;; // find matching segment ;; for (;;) { - block $breakMatchFirstChar loop $matchFirstChar - ;; v = buf32[icell+SEGMENT_INFO]; + block $nextSegment loop $findSegment + ;; y = buf32[icell+SEGMENT_INFO]; get_local $icell i32.load offset=8 align=4 - tee_local $v - ;; bl = char0 + (v & 0x00FFFFFF); + tee_local $y + ;; bl = char0 + (y & 0x00FFFFFF); i32.const 0x00FFFFFF i32.and get_local $char0 i32.add tee_local $bl - ;; if ( buf8[bl] === c ) { break; } + ;; if ( buf8[bl] === x ) { i32.load8_u - get_local $c + get_local $x i32.eq - br_if $breakMatchFirstChar + if + ;; y = (y >>> 24) - 1; + get_local $y + i32.const 24 + i32.shr_u + i32.const 1 + i32.sub + tee_local $y + ;; if ( n !== 0 ) { + if + ;; x = al + y; + get_local $y + get_local $al + i32.add + tee_local $x + ;; if ( x > aR ) { return 0; } + get_local $aR + i32.gt_u + br_if $matchNotFound + ;; for (;;) { + loop + ;; bl += 1; + get_local $bl + i32.const 1 + i32.add + tee_local $bl + ;; if ( buf8[bl] !== buf8[al] ) { return 0; } + i32.load8_u + get_local $al + i32.load8_u + i32.ne + br_if $matchNotFound + ;; al += 1; + get_local $al + i32.const 1 + i32.add + tee_local $al + ;; if ( al === x ) { break; } + get_local $x + i32.ne + br_if 0 + end + ;; } + end + br $nextSegment + end ;; icell = buf32[icell+CELL_OR]; get_local $icell i32.load offset=4 align=4 @@ -126,63 +166,9 @@ ;; if ( icell === 0 ) { return 0; } i32.eqz br_if $matchNotFound - br $matchFirstChar + br $findSegment ;; } end end - ;; // all characters in segment must match - ;; n = (v >>> 24) - 1; - get_local $v - i32.const 24 - i32.shr_u - i32.const 1 - i32.sub - tee_local $n - ;; if ( n !== 0 ) { - if - ;; const ar = al + n; - get_local $n - get_local $al - i32.add - tee_local $ar - ;; if ( ar > aR ) { return 0; } - get_local $aR - i32.gt_u - br_if $matchNotFound - ;; let i = al, j = bl + 1; - get_local $al - set_local $i - get_local $bl - i32.const 1 - i32.add - set_local $j - ;; do { - loop - ;; if ( buf8[i] !== buf8[j] ) { return 0; } - get_local $i - i32.load8_u - get_local $j - i32.load8_u - i32.ne - br_if $matchNotFound - ;; j += 1; i += 1; - get_local $j - i32.const 1 - i32.add - set_local $j - get_local $i - i32.const 1 - i32.add - tee_local $i - ;; } while ( i !== ar ); - get_local $ar - i32.ne - br_if 0 - end - ;; al = i; - get_local $i - set_local $al - ;; } - end ;; // next segment ;; icell = buf32[icell+CELL_AND]; get_local $icell @@ -190,33 +176,33 @@ i32.const 2 i32.shl tee_local $icell - ;; const v = buf32[icell+BCELL_EXTRA]; + ;; const x = buf32[icell+BCELL_EXTRA]; i32.load offset=8 align=4 - tee_local $v - ;; if ( v <= BCELL_EXTRA_MAX ) { + tee_local $x + ;; if ( x <= BCELL_EXTRA_MAX ) { i32.const 0x00FFFFFF i32.le_u if - ;; if ( v !== 0 && this.matchesExtra(ai, al, v) !== 0 ) { + ;; if ( x !== 0 && this.matchesExtra(ai, al, x) !== 0 ) { ;; return 1; ;; } - get_local $v + get_local $x if get_local $ai get_local $al - get_local $v + get_local $x call $matchesExtra br_if $matchFound end - ;; let inext = buf32[icell+BCELL_ALT_AND]; + ;; x = buf32[icell+BCELL_ALT_AND]; get_local $icell i32.load offset=4 align=4 i32.const 2 i32.shl - tee_local $inext - ;; if ( inext !== 0 && this.matchesLeft(inext, ai, al) !== 0 ) { + tee_local $x + ;; if ( x !== 0 && this.matchesLeft(x, ai, al) !== 0 ) { if - get_local $inext + get_local $x get_local $ai get_local $al call $matchesLeft @@ -260,14 +246,10 @@ (param $r i32) ;; right bound of match so far (result i32) ;; result: 0 = no match, 1 = match (local $char0 i32) - (local $c i32) - (local $v i32) (local $bl i32) - (local $n i32) - (local $al i32) (local $br i32) - (local $i i32) - (local $j i32) + (local $x i32) + (local $y i32) ;; const buf32 = this.buf32; ;; const buf8 = this.buf8; ;; const char0 = buf32[CHAR0_SLOT]; @@ -287,35 +269,76 @@ i32.const 1 i32.sub tee_local $ar - ;; c = buf8[ar]; + ;; x = buf8[ar]; i32.load8_u - set_local $c - ;; // find first segment with a first-character match + set_local $x + ;; // find matching segment ;; for (;;) { - block $breakMatchFirstChar loop $matchFirstChar - ;; v = buf32[icell+SEGMENT_INFO]; + block $nextSegment loop $findSegment + ;; y = buf32[icell+SEGMENT_INFO]; get_local $icell i32.load offset=8 align=4 - tee_local $v - ;; n = (v >>> 24) - 1; + tee_local $y + ;; br = char0 + (y & 0x00FFFFFF); + i32.const 0x00FFFFFF + i32.and + get_local $char0 + i32.add + tee_local $br + ;; y = (y >>> 24) - 1; + get_local $y i32.const 24 i32.shr_u i32.const 1 i32.sub - tee_local $n - ;; br = char0 + (v & 0x00FFFFFF) + n; - get_local $char0 - i32.add - get_local $v - i32.const 0x00FFFFFF - i32.and + tee_local $y + ;; br += y; i32.add tee_local $br - ;; if ( buf8[br] === c ) { break; } + ;; if ( buf8[br] === x ) { i32.load8_u - get_local $c + get_local $x i32.eq - br_if $breakMatchFirstChar + if + ;; // all characters in segment must match + ;; if ( y !== 0 ) { + get_local $y + if + ;; x = ar - y; + get_local $ar + get_local $y + i32.sub + tee_local $x + ;; if ( x < 0 ) { return 0; } + i32.const 0 + i32.lt_s + br_if $matchNotFound + ;; for (;;) { + loop + ;; ar -= 1; br -= 1; + ;; if ( buf8[ar] !== buf8[br] ) { return 0; } + get_local $ar + i32.const 1 + i32.sub + tee_local $ar + i32.load8_u + get_local $br + i32.const 1 + i32.sub + tee_local $br + i32.load8_u + i32.ne + br_if $matchNotFound + ;; if ( ar === x ) { break; } + get_local $ar + get_local $x + i32.ne + br_if 0 + end + ;; } + end + br $nextSegment + end ;; icell = buf32[icell+CELL_OR]; get_local $icell i32.load offset=4 align=4 @@ -325,54 +348,9 @@ ;; if ( icell === 0 ) { return 0; } i32.eqz br_if $matchNotFound - br $matchFirstChar + br $findSegment ;; } end end - ;; // all characters in segment must match - ;; if ( n !== 0 ) { - get_local $n - if - ;; const al = ar - n; - get_local $ar - get_local $n - i32.sub - tee_local $al - ;; if ( al < 0 ) { return 0; } - i32.const 0 - i32.lt_s - br_if $matchNotFound - ;; let i = ar, j = br; - get_local $ar - set_local $i - get_local $br - set_local $j - ;; do { - loop - ;; i -= 1; j -= 1; - ;; if ( buf8[i] !== buf8[j] ) { return 0; } - get_local $i - i32.const 1 - i32.sub - tee_local $i - i32.load8_u - get_local $j - i32.const 1 - i32.sub - tee_local $j - i32.load8_u - i32.ne - br_if $matchNotFound - ;; } while ( i !== al ); - get_local $i - get_local $al - i32.ne - br_if 0 - end - ;; ar = i; - get_local $i - set_local $ar - ;; } - end ;; // next segment ;; icell = buf32[icell+CELL_AND]; get_local $icell @@ -380,21 +358,21 @@ i32.const 2 i32.shl tee_local $icell - ;; const v = buf32[icell+BCELL_EXTRA]; + ;; const x = buf32[icell+BCELL_EXTRA]; i32.load offset=8 align=4 - tee_local $v - ;; if ( v <= BCELL_EXTRA_MAX ) { + tee_local $x + ;; if ( x <= BCELL_EXTRA_MAX ) { i32.const 0x00FFFFFF i32.le_u if - ;; if ( v !== 0 && this.matchesExtra(ar, r, v) !== 0 ) { + ;; if ( x !== 0 && this.matchesExtra(ar, r, x) !== 0 ) { ;; return 1; ;; } - get_local $v + get_local $x if get_local $ar get_local $r - get_local $v + get_local $x call $matchesExtra br_if $matchFound end @@ -431,9 +409,10 @@ (param $ix i32) ;; extra token (result i32) ;; result: 0 = no match, 1 = match (local $iu i32) ;; filter unit - ;; let iu; + block $fail + block $succeed ;; if ( ix !== 1 ) { - ;; iu = this.extraHandler(l, r, ix); + ;; const iu = this.extraHandler(l, r, ix); ;; if ( iu === 0 ) { return 0; } get_local $ix i32.const 1 @@ -445,10 +424,7 @@ call $extraHandler tee_local $iu i32.eqz - if - i32.const 0 - return - end + br_if $fail ;; } else { ;; iu = -1; else @@ -456,6 +432,10 @@ set_local $iu ;; } end + ;; this.buf32[RESULT_IU_SLOT] = iu; + i32.const 2076 + get_local $iu + i32.store align=4 ;; this.buf32[RESULT_L_SLOT] = l; i32.const 2068 get_local $l @@ -464,11 +444,11 @@ i32.const 2072 get_local $r i32.store align=4 - ;; this.buf32[RESULT_IU_SLOT] = iu; - i32.const 2076 - get_local $iu - i32.store align=4 + end ;; $succeed i32.const 1 + return + end ;; $fail + i32.const 0 ) ;; @@ -484,6 +464,8 @@ (param $needleLen i32) ;; number of characters to match (result i32) ;; result: 0 = no match, 1 = match (local $needleRight i32) + block $fail + block $succeed ;; ;; if ( haystackLeft < 0 || (haystackLeft + needleLen) > haystackRight ) { ;; return 0; @@ -491,38 +473,32 @@ get_local $haystackLeft i32.const 0 i32.lt_s - if - i32.const 0 - return - end + br_if $fail get_local $haystackLeft get_local $needleLen i32.add get_local $haystackRight i32.gt_u - if - i32.const 0 - return - end + br_if $fail ;; const charCodes = this.buf8; ;; needleLeft += this.buf32[CHAR0_SLOT]; get_local $needleLeft i32.const 2060 ;; CHAR0_SLOT memory address i32.load align=4 ;; CHAR0 memory address i32.add ;; needle memory address - ;; const needleRight = needleLeft + needleLen; tee_local $needleLeft + ;; const needleRight = needleLeft + needleLen; get_local $needleLen i32.add set_local $needleRight ;; while ( charCodes[haystackLeft] === charCodes[needleLeft] ) { - block $breakCompare loop $compare + loop $compare get_local $haystackLeft i32.load8_u get_local $needleLeft i32.load8_u - i32.ne - br_if $breakCompare + i32.ne + br_if $fail ;; needleLeft += 1; get_local $needleLeft i32.const 1 @@ -531,19 +507,21 @@ ;; if ( needleLeft === needleRight ) { return 1; } get_local $needleRight i32.eq - if - i32.const 1 - return - end + br_if $succeed ;; haystackLeft += 1; i32.const 1 get_local $haystackLeft i32.add set_local $haystackLeft br $compare - end end + end ;; } + ;; return 1; + end ;; $succeed + i32.const 1 + return ;; return 0; + end ;; $fail i32.const 0 ) @@ -564,6 +542,8 @@ (local $i i32) (local $j i32) (local $c0 i32) + block $fail + block $succeed ;; haystackEnd -= needleLen; get_local $haystackEnd get_local $needleLen @@ -572,10 +552,7 @@ ;; if ( haystackEnd < haystackLeft ) { return -1; } get_local $haystackLeft i32.lt_s - if - i32.const -1 - return - end + br_if $fail ;; needleLeft += this.buf32[CHAR0_SLOT]; get_local $needleLeft i32.const 2060 ;; CHAR0_SLOT memory address @@ -588,7 +565,7 @@ set_local $needleRight ;; const charCodes = this.buf8; ;; for (;;) { - block $breakMainLoop loop $mainLoop + loop $mainLoop ;; let i = haystackLeft; ;; let j = needleLeft; get_local $haystackLeft @@ -611,10 +588,7 @@ ;; if ( j === needleRight ) { return haystackLeft; } get_local $needleRight i32.eq - if - get_local $haystackLeft - return - end + br_if $succeed ;; i += 1; get_local $i i32.const 1 @@ -630,10 +604,15 @@ tee_local $haystackLeft ;; if ( haystackLeft === haystackEnd ) { break; } get_local $haystackEnd - i32.ne - br_if $mainLoop + i32.eq + br_if $fail + br $mainLoop ;; } - end end + end + end ;; $succeed + get_local $haystackLeft + return + end ;; $fail ;; return -1; i32.const -1 ) @@ -656,6 +635,8 @@ (local $i i32) (local $j i32) (local $c0 i32) + block $fail + block $succeed ;; let haystackLeft = haystackEnd - needleLen; get_local $haystackEnd get_local $needleLen @@ -664,10 +645,7 @@ ;; if ( haystackLeft < haystackBeg ) { return -1; } get_local $haystackBeg i32.lt_s - if - i32.const -1 - return - end + br_if $fail ;; needleLeft += this.buf32[CHAR0_SLOT]; get_local $needleLeft i32.const 2060 ;; CHAR0_SLOT memory address @@ -680,7 +658,7 @@ set_local $needleRight ;; const charCodes = this.buf8; ;; for (;;) { - block $breakMainLoop loop $mainLoop + loop $mainLoop ;; let i = haystackLeft; ;; let j = needleLeft; get_local $haystackLeft @@ -703,10 +681,7 @@ ;; if ( j === needleRight ) { return haystackLeft; } get_local $needleRight i32.eq - if - get_local $haystackLeft - return - end + br_if $succeed ;; i += 1; get_local $i i32.const 1 @@ -720,14 +695,18 @@ get_local $haystackLeft get_local $haystackBeg i32.eq - br_if $breakMainLoop + br_if $fail get_local $haystackLeft i32.const 1 i32.sub set_local $haystackLeft br $mainLoop ;; } - end end + end + end ;; $succeed + get_local $haystackLeft + return + end ;; $fail ;; return -1; i32.const -1 )