<commit_before>import { CevalCtrl, CevalOpts, CevalTechnology, Work, Step, Hovering, Started } from './types';

import { Pool, officialStockfish } from './pool';
import { defined, prop } from 'common';
import { storedProp } from 'common/storage';
import throttle from 'common/throttle';
import { povChances } from './winningChances';
import { sanIrreversible } from './util';


function is64Bit(): boolean {
  const x64 = ['x86_64', 'x86-64', 'Win64','x64', 'amd64', 'AMD64'];
  for (const substr of x64) if (navigator.userAgent.includes(substr)) return true;
  return navigator.platform === 'Linux x86_64' || navigator.platform === 'MacIntel';
}

function sharedWasmMemory(initial: number, maximum: number): WebAssembly.Memory | undefined {
  // TODO: In theory 32 bit should be supported just the same, but some 32 bit
  // browser builds seem to have trouble with WASMX. So for now detect and
  // require a 64 bit platform.
  if (!is64Bit()) return;

  // Atomics
  if (typeof Atomics !== 'object') return;

  // SharedArrayBuffer
  if (typeof SharedArrayBuffer !== 'function') return;

  // Shared memory
  const mem = new WebAssembly.Memory({shared: true, initial, maximum} as WebAssembly.MemoryDescriptor);
  if (!(mem.buffer instanceof SharedArrayBuffer)) return;

  // Structured cloning
  try {
    window.postMessage(mem, '*');
  } catch (e) {
    return;
  }

  return mem;
}

function median(values: number[]): number {
  values.sort((a, b) => a - b);
  const half = Math.floor(values.length / 2);
  return values.length % 2 ? values[half] : (values[half - 1] + values[half]) / 2.0;
}

export default function(opts: CevalOpts): CevalCtrl {
  const storageKey = (k: string) => {
    return opts.storageKeyPrefix ? `${opts.storageKeyPrefix}.${k}` : k;
  };

  // select wasmx with growable shared mem > wasmx > wasm > asmjs
  let technology: CevalTechnology = 'asmjs';
  let growableSharedMem = false;
  const source = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00);
  if (typeof WebAssembly === 'object' && typeof WebAssembly.validate === 'function' && WebAssembly.validate(source)) {
    technology = 'wasm'; // WebAssembly 1.0
    const sharedMem = sharedWasmMemory(8, 16);
    if (sharedMem) {
      technology = 'wasmx';
      if (!defined(window['crossOriginIsolated'])) window['crossOriginIsolated'] = true; // polyfill
      try {
        sharedMem.grow(8);
        growableSharedMem = true;
      } catch (e) { }
    }
  }

  const initialAllocationMaxThreads = officialStockfish(opts.variant.key) ? 2 : 1;
  const maxThreads = Math.min(Math.max((navigator.hardwareConcurrency || 1) - 1, 1), growableSharedMem ? 16 : initialAllocationMaxThreads);
  const threads = storedProp(storageKey('ceval.threads'), Math.min(Math.ceil((navigator.hardwareConcurrency || 1) / 4), maxThreads));

  const maxHashSize = Math.min((navigator.deviceMemory || 0.5) * 1024 / 16, growableSharedMem ? 512 : 16);
  const hashSize = storedProp(storageKey('ceval.hash-size'), 16);

  const minDepth = 6;
  const maxDepth = storedProp<number>(storageKey('ceval.max-depth'), 18);
  const multiPv = storedProp(storageKey('ceval.multipv'), opts.multiPvDefault || 1);
  const infinite = storedProp('ceval.infinite', false);
  let curEval: Tree.ClientEval | null = null;
  const allowed = prop(true);
  const enabled = prop(false);
  let started: Started | false = false;
  let lastStarted: Started | false = false; // last started object (for going deeper even if stopped)
  const hovering = prop<Hovering | null>(null);
  const isDeeper = prop(false);

  const pool = new Pool({
    technology,
    asmjs: 'vendor/stockfish.js/stockfish.js',
    wasm: 'vendor/stockfish.js/stockfish.wasm.js',
    wasmx: officialStockfish(opts.variant.key) ? 'vendor/stockfish.wasm/stockfish.js' : 'vendor/stockfish-mv.wasm/stockfish.js',
  }, {
    minDepth,<commit_msg>increase ceval max hash size to 1024m again<commit_after>import { CevalCtrl, CevalOpts, CevalTechnology, Work, Step, Hovering, Started } from './types';

import { Pool, officialStockfish } from './pool';
import { defined, prop } from 'common';
import { storedProp } from 'common/storage';
import throttle from 'common/throttle';
import { povChances } from './winningChances';
import { sanIrreversible } from './util';


function is64Bit(): boolean {
  const x64 = ['x86_64', 'x86-64', 'Win64','x64', 'amd64', 'AMD64'];
  for (const substr of x64) if (navigator.userAgent.includes(substr)) return true;
  return navigator.platform === 'Linux x86_64' || navigator.platform === 'MacIntel';
}

function sharedWasmMemory(initial: number, maximum: number): WebAssembly.Memory | undefined {
  // TODO: In theory 32 bit should be supported just the same, but some 32 bit
  // browser builds seem to have trouble with WASMX. So for now detect and
  // require a 64 bit platform.
  if (!is64Bit()) return;

  // Atomics
  if (typeof Atomics !== 'object') return;

  // SharedArrayBuffer
  if (typeof SharedArrayBuffer !== 'function') return;

  // Shared memory
  const mem = new WebAssembly.Memory({shared: true, initial, maximum} as WebAssembly.MemoryDescriptor);
  if (!(mem.buffer instanceof SharedArrayBuffer)) return;

  // Structured cloning
  try {
    window.postMessage(mem, '*');
  } catch (e) {
    return;
  }

  return mem;
}

function median(values: number[]): number {
  values.sort((a, b) => a - b);
  const half = Math.floor(values.length / 2);
  return values.length % 2 ? values[half] : (values[half - 1] + values[half]) / 2.0;
}

export default function(opts: CevalOpts): CevalCtrl {
  const storageKey = (k: string) => {
    return opts.storageKeyPrefix ? `${opts.storageKeyPrefix}.${k}` : k;
  };

  // select wasmx with growable shared mem > wasmx > wasm > asmjs
  let technology: CevalTechnology = 'asmjs';
  let growableSharedMem = false;
  const source = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00);
  if (typeof WebAssembly === 'object' && typeof WebAssembly.validate === 'function' && WebAssembly.validate(source)) {
    technology = 'wasm'; // WebAssembly 1.0
    const sharedMem = sharedWasmMemory(8, 16);
    if (sharedMem) {
      technology = 'wasmx';
      if (!defined(window['crossOriginIsolated'])) window['crossOriginIsolated'] = true; // polyfill
      try {
        sharedMem.grow(8);
        growableSharedMem = true;
      } catch (e) { }
    }
  }

  const initialAllocationMaxThreads = officialStockfish(opts.variant.key) ? 2 : 1;
  const maxThreads = Math.min(Math.max((navigator.hardwareConcurrency || 1) - 1, 1), growableSharedMem ? 16 : initialAllocationMaxThreads);
  const threads = storedProp(storageKey('ceval.threads'), Math.min(Math.ceil((navigator.hardwareConcurrency || 1) / 4), maxThreads));

  const maxHashSize = Math.min((navigator.deviceMemory || 0.25) * 1024 / 8, growableSharedMem ? 1024 : 16);
  const hashSize = storedProp(storageKey('ceval.hash-size'), 16);

  const minDepth = 6;
  const maxDepth = storedProp<number>(storageKey('ceval.max-depth'), 18);
  const multiPv = storedProp(storageKey('ceval.multipv'), opts.multiPvDefault || 1);
  const infinite = storedProp('ceval.infinite', false);
  let curEval: Tree.ClientEval | null = null;
  const allowed = prop(true);
  const enabled = prop(false);
  let started: Started | false = false;
  let lastStarted: Started | false = false; // last started object (for going deeper even if stopped)
  const hovering = prop<Hovering | null>(null);
  const isDeeper = prop(false);

  const pool = new Pool({
    technology,
    asmjs: 'vendor/stockfish.js/stockfish.js',
    wasm: 'vendor/stockfish.js/stockfish.wasm.js',
    wasmx: officialStockfish(opts.variant.key) ? 'vendor/stockfish.wasm/stockfish.js' : 'vendor/stockfish-mv.wasm/stockfish.js',
  }, {
    minDepth,
{'fraction_non_alphanumeric': 0.1414741190138118, 'fraction_numerical': 0.025429198399380404, 'mean_word_length': 4.097368421052631, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '770123', 'n_tokens_mistral': 2651, 'n_tokens_neox': 2450, 'n_words': 670}