Skip to content

Instantly share code, notes, and snippets.

@alexcrichton
Created January 15, 2019 22:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexcrichton/3f626d1996281bddfc01add09d831166 to your computer and use it in GitHub Desktop.
Save alexcrichton/3f626d1996281bddfc01add09d831166 to your computer and use it in GitHub Desktop.
[package]
name = "js-parser"
version = "0.1.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
edition = "2018"
[dependencies]
ressa = "*"
failure = "*"
resw = "*"
rayon = "*"
use std::fs;
use std::path::Path;
use std::str;
use failure::ResultExt;
use rayon::prelude::*;
fn main() {
walk(std::env::args().nth(1).unwrap().as_ref());
}
fn walk(dir: &Path) {
let files = dir.read_dir().unwrap()
.map(|e| e.unwrap().path())
.collect::<Vec<_>>();
files.par_iter()
.for_each(|path| {
if path.is_file() {
if path.extension() == Some("js".as_ref()) {
if let Err(e) = run(path) {
let path = path.strip_prefix("../gecko-dev").unwrap();
println!("* [{}](https://hg.mozilla.org/mozilla-central/file/tip/{})", e, path.display());
}
}
} else {
walk(&path)
}
});
}
fn run(file: &Path) -> Result<(), failure::Error> {
let contents = fs::read_to_string(file).context("read to string")?;
if contents.starts_with("// |jit-test| error: SyntaxError") {
return Ok(())
}
let mut dst = Vec::<u8>::new();
let mut out = resw::Writer::new(&mut dst);
let mut parts = Vec::new();
for part in ressa::Parser::new(&contents)
.map_err(|e| failure::format_err!("{}", e.to_string()))
.context("create")? {
let part = part
.map_err(|e| failure::format_err!("{}", e.to_string()))?;
out.write_part(&part).context("bad write")?;
parts.push(part);
}
let text = str::from_utf8(&dst).context("utf8")?;
for part in ressa::Parser::new(text).unwrap() {
let part = part
.map_err(|_e| failure::format_err!("failed to re-parse"))?;
if parts.len() == 0 {
failure::bail!("round-trip differed: {} vs {}", contents, text)
} else {
let expected = parts.remove(0);
if expected == part {
continue
}
println!("
<details>
```js
{}
```
vs
```js
{}
```
</details>
", contents, text);
failure::bail!("roundtrip differed");
}
}
Ok(())
}
if (!('oomTest' in this))
    quit();

oomTest(() => {
  var g = newGlobal({sameZoneAs: this});
  g.eval("\
    function f(){}; \
    getLcovInfo(); \
  ");
});

vs

if (!'oomTest' in this) quit();


oomTest(()  => {
    var g = newGlobal({
        sameZoneAs: this,
    });
    g.eval("function f(){}; getLcovInfo(); ");
});
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var appendToActual = function(s) {
    actual += s + ',';
}

if (!("gczeal" in this)) {
  gczeal = function() { }
}

if (!("schedulegc" in this)) {
  schedulegc = function() { }
}

if (!("gcslice" in this)) {
  gcslice = function() { }
}

if (!("selectforgc" in this)) {
  selectforgc = function() { }
}

if (!("verifyprebarriers" in this)) {
  verifyprebarriers = function() { }
}

if (!("verifypostbarriers" in this)) {
  verifypostbarriers = function() { }
}

if (!("gcPreserveCode" in this)) {
  gcPreserveCode = function() { }
}

vs

var appendToActual = (function(s) {
    actual += s + ',';
});

if (!"gczeal" in this) {
    gczeal = function() { };
}

if (!"schedulegc" in this) {
    schedulegc = function() { };
}

if (!"gcslice" in this) {
    gcslice = function() { };
}

if (!"selectforgc" in this) {
    selectforgc = function() { };
}

if (!"verifyprebarriers" in this) {
    verifyprebarriers = function() { };
}

if (!"verifypostbarriers" in this) {
    verifypostbarriers = function() { };
}

if (!"gcPreserveCode" in this) {
    gcPreserveCode = function() { };
}
// Test the source location info in a derived-class default constructor.

function W() { test(); }
class Z extends W {}  // line 4
class Y extends Z {}  // line 5

class X extends Y {}  // line 7

function test() {
    for (let frame of new Error().stack.split('\n')) {
        function lineNumber(frame) {
            return +frame.match(/(\d+):\d+$/)[1];
        }

        if (frame.startsWith("Z@"))
            assertEq(lineNumber(frame), 4);
        if (frame.startsWith("Y@"))
            assertEq(lineNumber(frame), 5);
        if (frame.startsWith("X@"))
            assertEq(lineNumber(frame), 7);
    }
}

new X;

vs

function W() {
    test();
}

class Z extends W {
}

class Y extends Z {
}

class X extends Y {
}

function test() {
    for (frame of new Error().stack.split('\n')) {
        function lineNumber(frame) {
            return +frame.match(/(\d+):\d+$/)[1];
        }

        if (frame.startsWith("Z@")) assertEq(lineNumber(frame), 4);


        if (frame.startsWith("Y@")) assertEq(lineNumber(frame), 5);


        if (frame.startsWith("X@")) assertEq(lineNumber(frame), 7);

    }
}

new X();
// |jit-test| skip-if: helperThreadCount() === 0 || !('oomAtAllocation' in this)

if ("gczeal" in this)
    gczeal(0);

eval("g=function() {}")
var lfGlobal = newGlobal();
for (lfLocal in this) {
    if (!(lfLocal in lfGlobal)) {
        lfGlobal[lfLocal] = this[lfLocal];
    }
}
lfGlobal.offThreadCompileScript(`
if (!("oomAtAllocation" in this && "resetOOMFailure" in this))
    gczeal(0);
function oomTest(f) {
    var i = 1;
    do {
        try {
            oomAtAllocation(i);
            f();
            more = resetOOMFailure();
        } catch (e) {
            more = resetOOMFailure();
        }
        i++;
    } while(more);
}
var g = newGlobal();
oomTest(function() { new revocable(); });
`);
try {
    lfGlobal.runOffThreadScript();
} catch(e) {
    // This can happen if we OOM while bailing out in Ion.
    assertEq(e, "out of memory");
}

vs

if ("gczeal" in this) gczeal(0);


eval("g=function() {}");

var lfGlobal = newGlobal();

for (lfLocal in this) {
    if (!lfLocal in lfGlobal) {
        lfGlobal[lfLocal] = this[lfLocal];
    }
}

lfGlobal.offThreadCompileScript(`
if (!("oomAtAllocation" in this && "resetOOMFailure" in this))
    gczeal(0);
function oomTest(f) {
    var i = 1;
    do {
        try {
            oomAtAllocation(i);
            f();
            more = resetOOMFailure();
        } catch (e) {
            more = resetOOMFailure();
        }
        i++;
    } while(more);
}
var g = newGlobal();
oomTest(function() { new revocable(); });
`);

try {
    lfGlobal.runOffThreadScript();
} catch (e) {
    assertEq(e, "out of memory");
}
// |jit-test| allow-oom
// Appending elements to a dense array should make the array sparse when the
// length exceeds the limit.

function test() {
  const MAX_DENSE_ELEMENTS_ALLOCATION = (1 << 28) - 1;
  const VALUES_PER_HEADER = 2;
  const MAX_DENSE_ELEMENTS_COUNT = MAX_DENSE_ELEMENTS_ALLOCATION - VALUES_PER_HEADER;
  const SPARSE_DENSITY_RATIO = 8;
  const MIN_DENSE = MAX_DENSE_ELEMENTS_COUNT / SPARSE_DENSITY_RATIO;
  const MARGIN = 16;

  let a = [];
  // Fill the beginning of array to make it keep dense until length exceeds
  // MAX_DENSE_ELEMENTS_COUNT.
  for (let i = 0; i < MIN_DENSE; i++)
    a[i] = i;

  // Skip from MIN_DENSE to MAX_DENSE_ELEMENTS_COUNT - MARGIN, to reduce the
  // time taken by test.

  // Fill the ending of array to make it sparse at MAX_DENSE_ELEMENTS_COUNT.
  for (let i = MAX_DENSE_ELEMENTS_COUNT - MARGIN; i < MAX_DENSE_ELEMENTS_COUNT + MARGIN; i++)
    a[i] = i;

  // Make sure the last element is defined.
  assertEq(a.length, MAX_DENSE_ELEMENTS_COUNT + MARGIN);
  assertEq(a[a.length - 1], MAX_DENSE_ELEMENTS_COUNT + MARGIN - 1);

  // Make sure elements around MAX_DENSE_ELEMENTS_COUNT are also defined.
  assertEq(a[MAX_DENSE_ELEMENTS_COUNT - 1], MAX_DENSE_ELEMENTS_COUNT - 1);
  assertEq(a[MAX_DENSE_ELEMENTS_COUNT], MAX_DENSE_ELEMENTS_COUNT);
  assertEq(a[MAX_DENSE_ELEMENTS_COUNT + 1], MAX_DENSE_ELEMENTS_COUNT + 1);
}

var config = getBuildConfiguration();
// Takes too long time on debug build.
if (!config.debug) {
  test();
}

vs

function test() {
    const MAX_DENSE_ELEMENTS_ALLOCATION = 1 << 28 - 1;
    const VALUES_PER_HEADER = 2;
    const MAX_DENSE_ELEMENTS_COUNT = MAX_DENSE_ELEMENTS_ALLOCATION - VALUES_PER_HEADER;
    const SPARSE_DENSITY_RATIO = 8;
    const MIN_DENSE = MAX_DENSE_ELEMENTS_COUNT / SPARSE_DENSITY_RATIO;
    const MARGIN = 16;
    let a = [];
    for (let i = 0;i < MIN_DENSE;i++) a[i] = i;
    for (let i = MAX_DENSE_ELEMENTS_COUNT - MARGIN;i < MAX_DENSE_ELEMENTS_COUNT + MARGIN;i++) a[i] = i;
    assertEq(a.length, MAX_DENSE_ELEMENTS_COUNT + MARGIN);
    assertEq(a[a.length - 1], MAX_DENSE_ELEMENTS_COUNT + MARGIN - 1);
    assertEq(a[MAX_DENSE_ELEMENTS_COUNT - 1], MAX_DENSE_ELEMENTS_COUNT - 1);
    assertEq(a[MAX_DENSE_ELEMENTS_COUNT], MAX_DENSE_ELEMENTS_COUNT);
    assertEq(a[MAX_DENSE_ELEMENTS_COUNT + 1], MAX_DENSE_ELEMENTS_COUNT + 1);
}

var config = getBuildConfiguration();

if (!config.debug) {
    test();
}
// Some experimental features are enabled only on nightly builds, and disabled
// on beta and release. Tests for these features should not simply disable
// themselves on all but nightly builds, because if we neglect to update such
// tests once the features cease to be experimental, we'll silently skip the
// tests on beta and release, even though they should run.

// Call the function f. On beta and release, expect it to throw an error that is
// an instance of error.
function nightlyOnly(error, f) {
  if (getBuildConfiguration().release_or_beta) {
    try {
      f();
      throw new Error("use of feature expected to fail on release and beta, but succeeded; please update test");
    } catch (e) {
      if (!(e instanceof error)) {
        throw e;
      }
      // All is well.
    }
  } else {
    f();
  }
}

vs

function nightlyOnly(error, f) {
    if (getBuildConfiguration().release_or_beta) {
        try {
            f();

            throw new Error("use of feature expected to fail on release and beta, but succeeded; please update test");
        } catch (e) {
            if (!e instanceof error) {
                throw e;
            }
        }
    } else {
        f();
    }
}
if (!wasmIsSupported())
    quit();

// We need to find the absolute path that ends like this:
//
//  js/src/jit-test/tests/wasm/spec/harness/
//
// because that's where the test harness lives.  Fortunately we are provided
// with |libdir|, which is a path that ends thusly
//
//  js/src/jit-test/lib/
//
// That is, it has a fixed offset relative to what we need.  So we can
// simply do this:

let harnessdir = libdir + "../tests/wasm/spec/harness/";

load(harnessdir + 'index.js');
load(harnessdir + 'wasm-constants.js');
load(harnessdir + 'wasm-module-builder.js');

function test(func, description) {
    let maybeErr;
    try {
        func();
    } catch(e) {
        maybeErr = e;
    }

    if (typeof maybeErr !== 'undefined') {
        throw new Error(`${description}: FAIL.
${maybeErr}
${maybeErr.stack}`);
    } else {
        print(`${description}: PASS.`);
    }
}

function promise_test(func, description) {
    let maybeError = null;
    func()
    .then(_ => {
        print(`${description}: PASS.`);
    })
    .catch(err => {
        print(`${description}: FAIL.
${err}`);
        maybeError = err;
    });
    drainJobQueue();
    if (maybeError)
        throw maybeError;
}

let assert_equals = assertEq;
let assert_true = (x, errMsg) => { assertEq(x, true); }
let assert_false = (x, errMsg) => { assertEq(x, false); }

function assert_unreached(description) {
    throw new Error(`unreachable:\n${description}`);
}

function assert_not_equals(actual, not_expected, description) {
    let caught = false;
    try {
        assertEq(actual, not_expected, description);
    } catch (e) {
        caught = true;
    };
    assertEq(caught, true, "assert_not_equals failed: " + description);
}

vs

if (!wasmIsSupported()) quit();


let harnessdir = libdir + "../tests/wasm/spec/harness/";

load(harnessdir + 'index.js');

load(harnessdir + 'wasm-constants.js');

load(harnessdir + 'wasm-module-builder.js');

function test(func, description) {
    let maybeErr;
    try {
        func();
    } catch (e) {
        maybeErr = e;
    }
    if (typeof maybeErr !== 'undefined') {
        throw new Error(`${description}: FAIL.
{maybeErr}
{maybeErr.stack}`);
    } else {
        print(`${description}: PASS.`);
    }
}

function promise_test(func, description) {
    let maybeError = null;
    func().then(_ => {
        print(`${description}: PASS.`);
    }).catch(err => {
        print(`${description}: FAIL.
{err}`);
        maybeError = err;
    });
    drainJobQueue();
    if (maybeError) throw maybeError;

}

let assert_equals = assertEq;

let assert_true = (x, errMsg)  => {
    assertEq(x, true);
};

let assert_false = (x, errMsg)  => {
    assertEq(x, false);
};

function assert_unreached(description) {
    throw new Error(`unreachable:\n${description}`);
}

function assert_not_equals(actual, not_expected, description) {
    let caught = false;
    try {
        assertEq(actual, not_expected, description);
    } catch (e) {
        caught = true;
    }
    ;
    assertEq(caught, true, "assert_not_equals failed: " + description);
}
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

load(libdir + "asserts.js");

const objects = [
    {},
    {a: 1, b: 2},
    {0: 1, 1: 2},
    {0: 1, 1: 2, a: 1},
    {0: 1, 1: 2, a: 1, b: 2},
    {1000000: 0, 1000001: 1},
    {0: 0, 1: 0, 1000000: 0, 1000001: 1},

    [],
    [0, 1, 2],
    [0, 15, 16],
    [{a: 0, b: 0}, {b: 0, a: 0}],
    [0, , , 1, 2],
    [, 1],
    [0,,],
    [,,],
]

for (const obj of objects) {
    assertDeepEq(deserialize(serialize(obj)), obj);
    assertDeepEq(deserialize(serialize(wrapWithProto(obj, null))), obj);
}

vs

load(libdir + "asserts.js");

const objects = [({}), ({
    a: 1,
    b: 2,
}), ({
    0: 1,
    1: 2,
}), ({
    0: 1,
    1: 2,
    a: 1,
}), ({
    0: 1,
    1: 2,
    a: 1,
    b: 2,
}), ({
    1000000: 0,
    1000001: 1,
}), ({
    0: 0,
    1: 0,
    1000000: 0,
    1000001: 1,
}), [], [0, 1, 2,], [0, 15, 16,], [({
    a: 0,
    b: 0,
}), ({
    b: 0,
    a: 0,
}),], [0,,, 1, 2,], [, 1,], [0,,], [,,],];

for (obj of objects) {
    assertDeepEq(deserialize(serialize(obj)), obj);

    assertDeepEq(deserialize(serialize(wrapWithProto(obj, null))), obj);
}
// These predicates are for tests that require a particular set of JIT options.

// Check if toggles match. Useful for tests that shouldn't be run if a
// different set of JIT toggles are set, since TBPL runs each jit-test
// multiple times with a variety of flags.
function jitTogglesMatch(opts) {
  var currentOpts = getJitCompilerOptions();
  for (var k in opts) {
    if (k.indexOf(".enable") > 0 && opts[k] != currentOpts[k])
      return false;
  }

  // ARM64 does not yet have an Ion code generator, so return false if
  // ion.enable is requested.
  var conf = getBuildConfiguration();
  if (conf['arm64'] && opts['ion.enable'])
    return false;

  return true;
}

// Run fn under a particular set of JIT options.
function withJitOptions(opts, fn) {
  var oldOpts = getJitCompilerOptions();
  for (var k in opts)
    setJitCompilerOption(k, opts[k]);
  try {
    fn();
  } finally {
    for (var k in oldOpts)
      setJitCompilerOption(k, oldOpts[k]);
  }
}

// N.B. Ion opts *must come before* baseline opts because there's some kind of
// "undo eager compilation" logic. If we don't set the baseline warmup-counter
// *after* the Ion warmup-counter we end up setting the baseline warmup-counter
// to be the default if we hit the "undo eager compilation" logic.
var Opts_BaselineEager =
    {
      'ion.enable': 1,
      'ion.warmup.trigger': 100,
      'baseline.enable': 1,
      'baseline.warmup.trigger': 0,
      'offthread-compilation.enable': 1
    };

// Checking for offthread compilation being off is often helpful if the test
// requires a function be Ion compiled. Each individual test will usually
// finish before the Ion compilation thread has a chance to attach the
// compiled code.
var Opts_IonEagerNoOffthreadCompilation =
    {
      'ion.enable': 1,
      'ion.warmup.trigger': 0,
      'baseline.enable': 1,
      'baseline.warmup.trigger': 0,
      'offthread-compilation.enable': 0,
    };

var Opts_Ion2NoOffthreadCompilation =
    {
      'ion.enable': 1,
      'ion.warmup.trigger': 2,
      'baseline.enable': 1,
      'baseline.warmup.trigger': 1,
      'offthread-compilation.enable': 0
    };

var Opts_NoJits =
    {
      'ion.enable': 0,
      'ion.warmup.trigger': 0,
      'baseline.warmup.trigger': 0,
      'baseline.enable': 0,
      'offthread-compilation.enable': 0
    };

vs

function jitTogglesMatch(opts) {
    var currentOpts = getJitCompilerOptions();
    for (k in opts) {
        if (k.indexOf(".enable") > 0 && opts[k] != currentOpts[k]) return false;

    }
    var conf = getBuildConfiguration();
    if (conf['arm64'] && opts['ion.enable']) return false;

    return true;
}

function withJitOptions(opts, fn) {
    var oldOpts = getJitCompilerOptions();
    for (k in opts) setJitCompilerOption(k, opts[k]);
    try {
        fn();
    } finally {
        for (k in oldOpts) setJitCompilerOption(k, oldOpts[k]);
    }
}

var Opts_BaselineEager = ({
    'ion.enable': 1,
    'ion.warmup.trigger': 100,
    'baseline.enable': 1,
    'baseline.warmup.trigger': 0,
    'offthread-compilation.enable': 1,
});

var Opts_IonEagerNoOffthreadCompilation = ({
    'ion.enable': 1,
    'ion.warmup.trigger': 0,
    'baseline.enable': 1,
    'baseline.warmup.trigger': 0,
    'offthread-compilation.enable': 0,
});

var Opts_Ion2NoOffthreadCompilation = ({
    'ion.enable': 1,
    'ion.warmup.trigger': 2,
    'baseline.enable': 1,
    'baseline.warmup.trigger': 1,
    'offthread-compilation.enable': 0,
});

var Opts_NoJits = ({
    'ion.enable': 0,
    'ion.warmup.trigger': 0,
    'baseline.warmup.trigger': 0,
    'baseline.enable': 0,
    'offthread-compilation.enable': 0,
});
function evalWithCache(code, ctx) {
  ctx = ctx || {};
  ctx = Object.create(ctx, {
    fileName: { value: "evalWithCacheCode.js" },
    lineNumber: { value: 0 }
  });
  code = code instanceof Object ? code : cacheEntry(code);

  var incremental = ctx.incremental || false;

  // We create a new global ...
  if (!("global" in ctx))
    ctx.global = newGlobal({ cloneSingletons: !incremental });

  if (!("isRunOnce" in ctx))
    ctx.isRunOnce = true;

  var ctx_save;
  if (incremental)
    ctx_save = Object.create(ctx, {saveIncrementalBytecode: { value: true } });
  else
    ctx_save = Object.create(ctx, {saveBytecode: { value: true } });

  // Fetch the verification function from the evaluation context.  This function
  // is used to assert the state of the script/function after each run of the
  // evaluate function.
  var checkAfter = ctx.checkAfter || function(ctx) {};

  // The generation counter is used to represent environment variations which
  // might cause the program to run differently, and thus to have a different
  // set of functions executed.
  ctx.global.generation = 0;
  var res1 = evaluate(code, ctx_save);
  checkAfter(ctx);

  ctx.global.generation = 1;
  var res2 = evaluate(code, Object.create(ctx_save, {loadBytecode: { value: true } }));
  checkAfter(ctx);

  ctx.global.generation = 2;
  var res3 = evaluate(code, Object.create(ctx, {loadBytecode: { value: true } }));
  checkAfter(ctx);

  ctx.global.generation = 3;
  var res0 = evaluate(code, ctx);
  checkAfter(ctx);

  if (ctx.assertEqResult) {
    assertEq(res0, res1);
    assertEq(res0, res2);
    assertEq(res0, res3);
  }

  if (ctx.checkFrozen) {
    assertEq(Object.isFrozen(res0), Object.isFrozen(res1));
    assertEq(Object.isFrozen(res0), Object.isFrozen(res2));
    assertEq(Object.isFrozen(res0), Object.isFrozen(res3));
  }
}

vs

function evalWithCache(code, ctx) {
    ctx = ctx || {    };
    ctx = Object.create(ctx, {
        fileName: {
            value: "evalWithCacheCode.js",
        },
        lineNumber: {
            value: 0,
        },
    });
    code = code instanceof Object ? code : cacheEntry(code);
    var incremental = ctx.incremental || false;
    if (!"global" in ctx) ctx.global = newGlobal({
        cloneSingletons: !incremental,
    });

    if (!"isRunOnce" in ctx) ctx.isRunOnce = true;

    var ctx_save;
    if (incremental) ctx_save = Object.create(ctx, {
        saveIncrementalBytecode: {
            value: true,
        },
    });
 else ctx_save = Object.create(ctx, {
        saveBytecode: {
            value: true,
        },
    });

    var checkAfter = ctx.checkAfter || function(ctx) { };
    ctx.global.generation = 0;
    var res1 = evaluate(code, ctx_save);
    checkAfter(ctx);
    ctx.global.generation = 1;
    var res2 = evaluate(code, Object.create(ctx_save, {
        loadBytecode: {
            value: true,
        },
    }));
    checkAfter(ctx);
    ctx.global.generation = 2;
    var res3 = evaluate(code, Object.create(ctx, {
        loadBytecode: {
            value: true,
        },
    }));
    checkAfter(ctx);
    ctx.global.generation = 3;
    var res0 = evaluate(code, ctx);
    checkAfter(ctx);
    if (ctx.assertEqResult) {
        assertEq(res0, res1);

        assertEq(res0, res2);

        assertEq(res0, res3);
    }
    if (ctx.checkFrozen) {
        assertEq(Object.isFrozen(res0), Object.isFrozen(res1));

        assertEq(Object.isFrozen(res0), Object.isFrozen(res2));

        assertEq(Object.isFrozen(res0), Object.isFrozen(res3));
    }
}
// Set breakpoints "everywhere" in a function, then call the function and check that
// the breakpoints were added are at the expected columns, and the breakpoints
// were executed in th expected order.
//
// `code` is a JS Script. The final line should define a function `f` to validate.
// `expectedBpts` is a string of spaces and carets ('^'). Throws if we don't hit
// breakpoints on exactly the columns indicated by the carets.
// `expectedOrdering` is a string of integer indices for the offsets that are
// executed, in the order that then are executed. Test code can also push
// additional items into this string using items.push("!").
function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) {
    if (expectedOrdering === null) {
        // The default ordering simply runs the breakpoints in order.
        expectedOrdering = Array.from(expectedBpts.match(/\^/g), (_, i) => i).join(" ");
    }

    // Define the function `f` in a new global.
    const global = newGlobal();

    const lines = code.split(/\r?\n|\r]/g);
    const initCode = lines.slice(0, -1).join("\n");
    const execCode = lines[lines.length - 1];

    // Treat everything but the last line as initialization code.
    global.eval(initCode);

    // Run the test code itself.
    global.eval(execCode);

    // Allow some tests to append to a log that will show up in expected ordering.
    const hits = global.hits = [];
    const bpts = new Set();

    // Set breakpoints everywhere and call the function.
    const dbg = new Debugger;
    let debuggeeFn = dbg.addDebuggee(global).makeDebuggeeValue(global.f);
    if (debuggeeFn.isBoundFunction) {
        debuggeeFn = debuggeeFn.boundTargetFunction;
    }

    const { script } = debuggeeFn;
    for (const offset of script.getAllColumnOffsets()) {
        assertEq(offset.lineNumber, 1);
        assertEq(offset.columnNumber < execCode.length, true);
        bpts.add(offset.columnNumber);

        script.setBreakpoint(offset.offset, {
            hit(frame) {
                hits.push(offset.columnNumber);
            },
        });
    }
    global.f(3);

    const actualBpts = Array.from(execCode, (_, i) => {
        return bpts.has(i) ? "^" : " ";
    }).join("");

    if (actualBpts.trimEnd() !== expectedBpts.trimEnd()) {
        throw new Error(`Assertion failed:
                     code: ${execCode}
            expected bpts: ${expectedBpts}
              actual bpts: ${actualBpts}\n`);
    }

    const indexLookup = new Map(
        Array.from(bpts).sort().map((col, i) => [col, i]));
    const actualOrdering = hits
        .map(item => typeof item === "number" ? indexLookup.get(item) : item)
        .join(" ");

    if (actualOrdering.trimEnd() !== expectedOrdering.trimEnd()) {
        throw new Error(`Assertion failed:
                     code: ${execCode}
                     bpts: ${expectedBpts}
           expected order: ${expectedOrdering}
             actual order: ${actualOrdering}\n`);
    }
}

vs

function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) {
    if (expectedOrdering === null) {
        expectedOrdering = Array.from(expectedBpts.match(/\^/g), (_, i)  => i).join(" ");
    }
    const global = newGlobal();
    const lines = code.split(/\r?\n|\r]/g);
    const initCode = lines.slice(0, -1).join("\n");
    const execCode = lines[lines.length - 1];
    global.eval(initCode);
    global.eval(execCode);
    const hits = global.hits = [];
    const bpts = new Set();
    const dbg = new Debugger();
    let debuggeeFn = dbg.addDebuggee(global).makeDebuggeeValue(global.f);
    if (debuggeeFn.isBoundFunction) {
        debuggeeFn = debuggeeFn.boundTargetFunction;
    }
    const {script,    } = debuggeeFn;
    for (offset of script.getAllColumnOffsets()) {
        assertEq(offset.lineNumber, 1);

        assertEq(offset.columnNumber < execCode.length, true);

        bpts.add(offset.columnNumber);

        script.setBreakpoint(offset.offset, {
            hit: function(frame) {
                hits.push(offset.columnNumber);
            },
        });
    }
    global.f(3);
    const actualBpts = Array.from(execCode, (_, i)  => {
        return bpts.has(i) ? "^" : " ";
    }).join("");
    if (actualBpts.trimEnd() !== expectedBpts.trimEnd()) {
        throw new Error(`Assertion failed:
                     code: ${execCode}
            expected bpts: {expectedBpts}
              actual bpts: {actualBpts}\n`);
    }
    const indexLookup = new Map(Array.from(bpts).sort().map((col, i)  => [col, i,]));
    const actualOrdering = hits.map(item => typeof item === "number" ? indexLookup.get(item) : item).join(" ");
    if (actualOrdering.trimEnd() !== expectedOrdering.trimEnd()) {
        throw new Error(`Assertion failed:
                     code: ${execCode}
                     bpts: {expectedBpts}
           expected order: {expectedOrdering}
             actual order: {actualOrdering}\n`);
    }
}
// Functions for checking results returned by Debugger.Memory.prototype.takeCensus.

const Census = {};

(function () {

  // Census.walkCensus(subject, name, walker[, ignore])
  //
  // Use |walker| to check |subject|, a census object of the sort returned by
  // Debugger.Memory.prototype.takeCensus: a tree of objects with integers at the
  // leaves. Use |name| as the name for |subject| in diagnostic messages. Return
  // the number of leaves of |subject| we visited.
  //
  // A walker is an object with three methods:
  //
  // - enter(prop): Return the walker we should use to check the property of the
  //   subject census named |prop|. This is for recursing into the subobjects of
  //   the subject.
  //
  // - done(ignore): Called after we have called 'enter' on every property of
  //   the subject. Passed the |ignore| set of properties.
  //
  // - check(value): Check |value|, a leaf in the subject.
  //
  // Walker methods are expected to simply throw if a node we visit doesn't look
  // right.
  //
  // The optional |ignore| parameter allows you to specify a |Set| of property
  // names which should be ignored. The walker will not traverse such
  // properties.
  Census.walkCensus = (subject, name, walker, ignore = new Set()) =>
    walk(subject, name, walker, ignore, 0);

  function walk(subject, name, walker, ignore, count) {
    if (typeof subject === 'object') {
      print(name);
      for (let prop in subject) {
        if (ignore.has(prop)) {
          continue;
        }
        count = walk(subject[prop],
                     name + "[" + uneval(prop) + "]",
                     walker.enter(prop),
                     ignore,
                     count);
      }
      walker.done(ignore);
    } else {
      print(name + " = " + uneval(subject));
      walker.check(subject);
      count++;
    }

    return count;
  }

  // A walker that doesn't check anything.
  Census.walkAnything = {
    enter: () => Census.walkAnything,
    done: () => undefined,
    check: () => undefined
  };

  // A walker that requires all leaves to be zeros.
  Census.assertAllZeros = {
    enter: () => Census.assertAllZeros,
    done: () => undefined,
    check: elt => assertEq(elt, 0)
  };

  function expectedObject() {
    throw "Census mismatch: subject has leaf where basis has nested object";
  }

  function expectedLeaf() {
    throw "Census mismatch: subject has nested object where basis has leaf";
  }

  // Return a function that, given a 'basis' census, returns a census walker that
  // compares the subject census against the basis. The returned walker calls the
  // given |compare|, |missing|, and |extra| functions as follows:
  //
  // - compare(subjectLeaf, basisLeaf): Check a leaf of the subject against the
  //   corresponding leaf of the basis.
  //
  // - missing(prop, value): Called when the subject is missing a property named
  //   |prop| which is present in the basis with value |value|.
  //
  // - extra(prop): Called when the subject has a property named |prop|, but the
  //   basis has no such property. This should return a walker that can check
  //   the subject's value.
  function makeBasisChecker({compare, missing, extra}) {
    return function makeWalker(basis) {
      if (typeof basis === 'object') {
        var unvisited = new Set(Object.getOwnPropertyNames(basis));
        return {
          enter: prop => {
            unvisited.delete(prop);
            if (prop in basis) {
              return makeWalker(basis[prop]);
            } else {
              return extra(prop);
            }
          },

          done: ignore => [...unvisited].filter(p => !ignore.has(p)).forEach(p => missing(p, basis[p])),
          check: expectedObject
        };
      } else {
        return {
          enter: expectedLeaf,
          done: expectedLeaf,
          check: elt => compare(elt, basis)
        };
      }
    };
  }

  function missingProp(prop) {
    throw "Census mismatch: subject lacks property present in basis: " + uneval(prop);
  }

  function extraProp(prop) {
    throw "Census mismatch: subject has property not present in basis: " + uneval(prop);
  }

  // Return a walker that checks that the subject census has counts all equal to
  // |basis|.
  Census.assertAllEqual = makeBasisChecker({
    compare: assertEq,
    missing: missingProp,
    extra: extraProp
  });

  // Return a walker that checks that the subject census has at least as many
  // items of each category as |basis|.
  Census.assertAllNotLessThan = makeBasisChecker({
    compare: (subject, basis) => assertEq(subject >= basis, true),
    missing: missingProp,
    extra: () => Census.walkAnything
  });

  // Return a walker that checks that the subject census has at most as many
  // items of each category as |basis|.
  Census.assertAllNotMoreThan = makeBasisChecker({
    compare: (subject, basis) => assertEq(subject <= basis, true),
    missing: missingProp,
    extra: () => Census.walkAnything
  });

  // Return a walker that checks that the subject census has within |fudge|
  // items of each category of the count in |basis|.
  Census.assertAllWithin = function (fudge, basis) {
    return makeBasisChecker({
      compare: (subject, basis) => assertEq(Math.abs(subject - basis) <= fudge, true),
      missing: missingProp,
      extra: () => Census.walkAnything
    })(basis);
  }

})();

vs

const Census = ({});

(function() {
    Census.walkCensus = (subject, name, walker, ignore = new Set())  => walk(subject, name, walker, ignore, 0);
    function walk(subject, name, walker, ignore, count) {
        if (typeof subject === 'object') {
            print(name);

            for (prop in subject) {
                if (ignore.has(prop)) {
                    continue;
                }

                count = walk(subject[prop], name + "[" + uneval(prop) + "]", walker.enter(prop), ignore, count);
            }

            walker.done(ignore);
        } else {
            print(name + " = " + uneval(subject));

            walker.check(subject);

            count++;
        }
        return count;
    }
    Census.walkAnything = {
        enter: ()  => Census.walkAnything,
        done: ()  => undefined,
        check: ()  => undefined,
    };
    Census.assertAllZeros = {
        enter: ()  => Census.assertAllZeros,
        done: ()  => undefined,
        check: elt => assertEq(elt, 0),
    };
    function expectedObject() {
        throw "Census mismatch: subject has leaf where basis has nested object";
    }
    function expectedLeaf() {
        throw "Census mismatch: subject has nested object where basis has leaf";
    }
    function makeBasisChecker({compare, missing, extra,    }) {
        return function makeWalker(basis) {
            if (typeof basis === 'object') {
                var unvisited = new Set(Object.getOwnPropertyNames(basis));

                return {
                    enter: prop => {
                        unvisited.delete(prop);
                        if (prop in basis) {
                            return makeWalker(basis[prop]);
                        } else {
                            return extra(prop);
                        }
                    },
                    done: ignore => [...unvisited,].filter(p => !ignore.has(p)).forEach(p => missing(p, basis[p])),
                    check: expectedObject,
                };
            } else {
                return {
                    enter: expectedLeaf,
                    done: expectedLeaf,
                    check: elt => compare(elt, basis),
                };
            }
        };
    }
    function missingProp(prop) {
        throw "Census mismatch: subject lacks property present in basis: " + uneval(prop);
    }
    function extraProp(prop) {
        throw "Census mismatch: subject has property not present in basis: " + uneval(prop);
    }
    Census.assertAllEqual = makeBasisChecker({
        compare: assertEq,
        missing: missingProp,
        extra: extraProp,
    });
    Census.assertAllNotLessThan = makeBasisChecker({
        compare: (subject, basis)  => assertEq(subject >= basis, true),
        missing: missingProp,
        extra: ()  => Census.walkAnything,
    });
    Census.assertAllNotMoreThan = makeBasisChecker({
        compare: (subject, basis)  => assertEq(subject <= basis, true),
        missing: missingProp,
        extra: ()  => Census.walkAnything,
    });
    Census.assertAllWithin = function(fudge, basis) {
        return makeBasisChecker({
            compare: (subject, basis)  => assertEq(Math.abs(subject - basis) <= fudge, true),
            missing: missingProp,
            extra: ()  => Census.walkAnything,
        })(basis);
    };
})();
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

var map = new Map();
map.set("self", map);

var magic = deserialize(serialize(map));
assertEq(magic.get("self"), magic);
assertEq(magic.size, 1);

map = new Map();
map.set(map, "self");

magic = deserialize(serialize(map));
assertEq(magic.get(magic), "self");
assertEq(magic.size, 1);

var values = [
    "a", "\uDEFF", undefined, null, -3.5, true, false, NaN, 155, -2
]

map = new Map();
for (var value of values) {
    map.set(value, value);
}

magic = deserialize(serialize(map));
var i = 0;
for (value of magic) {
    assertEq(value[0], value[1]);
    assertEq(value[0], values[i++]);
}

assertEq([...map.keys()].toSource(), [...magic.keys()].toSource());
assertEq([...map.values()].toSource(), [...magic.values()].toSource());

var obj = {a: 1};
obj.map = new Map();
obj.map.set("obj", obj);

magic = deserialize(serialize(obj));

assertEq(magic.map.get("obj"), magic);
assertEq(magic.a, 1);

map = new Map();
map.set("a", new Number(1));
map.set("b", new String("aaaa"));
map.set("c", new Date(NaN));

magic = deserialize(serialize(map));

assertEq(magic.get("a").valueOf(), 1);
assertEq(magic.get("b").valueOf(), "aaaa");
assertEq(magic.get("c").valueOf(), NaN);

assertEq([...magic.keys()].toSource(), ["a", "b", "c"].toSource());

map = new Map();
map.set("x", new Map());
map.get("x").set("x", map);
map.get("x").set("b", null);

magic = deserialize(serialize(map));

assertEq(magic.get("x").get("x"), magic);
assertEq(magic.get("x").get("b"), null);

map = new Map()
map.set({a: 1}, "b");

magic = deserialize(serialize(map));

obj = [...magic.keys()][0];
assertEq(obj.a, 1);
assertEq(magic.get(obj), "b");

// Make sure expandos aren't cloned (Bug 1041172)
map = new Map();
map.a = "aaaaa";
magic = deserialize(serialize(map));
assertEq("a" in magic, false);
assertEq(Object.keys(magic).length, 0);

// Busted [[Prototype]] shouldn't matter
map = new Map();
Object.setPrototypeOf(map, null);
Map.prototype.set.call(map, "self", map);
magic = deserialize(serialize(map));
assertEq(magic.get("self"), magic);
assertEq(magic.size, 1);

// Can't fuzz around with Map after it is cloned
obj = {
    a: new Map(),
    get b() {
        obj.a.delete("test");
        return "invoked";
    }
}
obj.a.set("test", "hello");
assertEq(obj.a.has("test"), true);
magic = deserialize(serialize(obj));
assertEq(obj.a.has("test"), false);
assertEq(magic.a.size, 1);
assertEq(magic.a.get("test"), "hello");
assertEq([...magic.a.keys()].toString(), "test");
assertEq(magic.b, "invoked");

vs

var map = new Map();

map.set("self", map);

var magic = deserialize(serialize(map));

assertEq(magic.get("self"), magic);

assertEq(magic.size, 1);

map = new Map();

map.set(map, "self");

magic = deserialize(serialize(map));

assertEq(magic.get(magic), "self");

assertEq(magic.size, 1);

var values = ["a", "\uDEFF", undefined, null, -3.5, true, false, NaN, 155, -2,];

map = new Map();

for (value of values) {
    map.set(value, value);
}

magic = deserialize(serialize(map));

var i = 0;

for (value of magic) {
    assertEq(value[0], value[1]);

    assertEq(value[0], values[i++]);
}

assertEq([...map.keys(),].toSource(), [...magic.keys(),].toSource());

assertEq([...map.values(),].toSource(), [...magic.values(),].toSource());

var obj = ({
    a: 1,
});

obj.map = new Map();

obj.map.set("obj", obj);

magic = deserialize(serialize(obj));

assertEq(magic.map.get("obj"), magic);

assertEq(magic.a, 1);

map = new Map();

map.set("a", new Number(1));

map.set("b", new String("aaaa"));

map.set("c", new Date(NaN));

magic = deserialize(serialize(map));

assertEq(magic.get("a").valueOf(), 1);

assertEq(magic.get("b").valueOf(), "aaaa");

assertEq(magic.get("c").valueOf(), NaN);

assertEq([...magic.keys(),].toSource(), ["a", "b", "c",].toSource());

map = new Map();

map.set("x", new Map());

map.get("x").set("x", map);

map.get("x").set("b", null);

magic = deserialize(serialize(map));

assertEq(magic.get("x").get("x"), magic);

assertEq(magic.get("x").get("b"), null);

map = new Map();

map.set(({
    a: 1,
}), "b");

magic = deserialize(serialize(map));

obj = [...magic.keys(),][0];

assertEq(obj.a, 1);

assertEq(magic.get(obj), "b");

map = new Map();

map.a = "aaaaa";

magic = deserialize(serialize(map));

assertEq("a" in magic, false);

assertEq(Object.keys(magic).length, 0);

map = new Map();

Object.setPrototypeOf(map, null);

Map.prototype.set.call(map, "self", map);

magic = deserialize(serialize(map));

assertEq(magic.get("self"), magic);

assertEq(magic.size, 1);

obj = ({
    a: new Map(),
    get b() {
        obj.a.delete("test");
        return "invoked";
    },
});

obj.a.set("test", "hello");

assertEq(obj.a.has("test"), true);

magic = deserialize(serialize(obj));

assertEq(obj.a.has("test"), false);

assertEq(magic.a.size, 1);

assertEq(magic.a.get("test"), "hello");

assertEq([...magic.a.keys(),].toString(), "test");

assertEq(magic.b, "invoked");
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


load(libdir + "../../tests/non262/shell.js");

if (typeof assertWarning === 'undefined') {
    var assertWarning = function assertWarning(f, pattern) {
        var hadWerror = options().split(",").indexOf("werror") !== -1;

        // Ensure the "werror" option is disabled.
        if (hadWerror)
            options("werror");

        try {
            f();
        } catch (exc) {
            if (hadWerror)
                options("werror");

            print("assertWarning: Unexpected exception calling " + f +
                  " with warnings-as-errors disabled");
            throw exc;
        }

        // Enable the "werror" option.
        options("werror");

        try {
            f();
        } catch (exc) {
            if (!String(exc).match(pattern))
                throw new Error(`assertWarning failed: "${exc}" does not match "${pattern}"`);
            return;
        } finally {
            if (!hadWerror)
                options("werror");
        }
        throw new Error("assertWarning failed: no warning");
    };
}

if (typeof assertNoWarning === 'undefined') {
    var assertNoWarning = function assertNoWarning(f, msg) {
        // Ensure the "werror" option is enabled.
        var hadWerror = options().split(",").indexOf("werror") !== -1;
        if (!hadWerror)
            options("werror");

        try {
            f();
        } catch (exc) {
            if (msg)
                print("assertNoWarning: " + msg);
            print("assertNoWarning: Unexpected exception calling " + f +
                  "with warnings-as-errors enabled");
            throw exc;
        } finally {
            if (!hadWerror)
                options("werror");
        }
    };
}

if (typeof assertErrorMessage === 'undefined') {
    var assertErrorMessage = function assertErrorMessage(f, ctor, test) {
        try {
            f();
        } catch (e) {
            if (!(e instanceof ctor))
                throw new Error("Assertion failed: expected exception " + ctor.name + ", got " + e);
            if (typeof test == "string") {
                if (test != e.message)
                    throw new Error("Assertion failed: expected " + test + ", got " + e.message);
            } else {
                if (!test.test(e.message))
                    throw new Error("Assertion failed: expected " + test.toString() + ", got " + e.message);
            }
            return;
        }
        throw new Error("Assertion failed: expected exception " + ctor.name + ", no exception thrown");
    };
}

if (typeof assertTypeErrorMessage === 'undefined') {
    var assertTypeErrorMessage = function assertTypeErrorMessage(f, test) {
      assertErrorMessage(f, TypeError, test);
    };
}

if (typeof assertRangeErrorMessage === 'undefined') {
    var assertRangeErrorMessage = function assertRangeErrorMessage(f, test) {
      assertErrorMessage(f, RangeError, test);
    };
}

vs

load(libdir + "../../tests/non262/shell.js");

if (typeof assertWarning === 'undefined') {
    var assertWarning = function assertWarning(f, pattern) {
        var hadWerror = options().split(",").indexOf("werror") !== -1;
        if (hadWerror) options("werror");

        try {
            f();
        } catch (exc) {
            if (hadWerror) options("werror");


            print("assertWarning: Unexpected exception calling " + f + " with warnings-as-errors disabled");

            throw exc;
        }
        options("werror");
        try {
            f();
        } catch (exc) {
            if (!String(exc).match(pattern)) throw new Error(`assertWarning failed: "${exc}" does not match "{pattern}"`);


            return;
        } finally {
            if (!hadWerror) options("werror");

        }
        throw new Error("assertWarning failed: no warning");
    };
}

if (typeof assertNoWarning === 'undefined') {
    var assertNoWarning = function assertNoWarning(f, msg) {
        var hadWerror = options().split(",").indexOf("werror") !== -1;
        if (!hadWerror) options("werror");

        try {
            f();
        } catch (exc) {
            if (msg) print("assertNoWarning: " + msg);


            print("assertNoWarning: Unexpected exception calling " + f + "with warnings-as-errors enabled");

            throw exc;
        } finally {
            if (!hadWerror) options("werror");

        }
    };
}

if (typeof assertErrorMessage === 'undefined') {
    var assertErrorMessage = function assertErrorMessage(f, ctor, test) {
        try {
            f();
        } catch (e) {
            if (!e instanceof ctor) throw new Error("Assertion failed: expected exception " + ctor.name + ", got " + e);


            if (typeof test == "string") {
                if (test != e.message) throw new Error("Assertion failed: expected " + test + ", got " + e.message);

            } else {
                if (!test.test(e.message)) throw new Error("Assertion failed: expected " + test.toString() + ", got " + e.message);

            }

            return;
        }
        throw new Error("Assertion failed: expected exception " + ctor.name + ", no exception thrown");
    };
}

if (typeof assertTypeErrorMessage === 'undefined') {
    var assertTypeErrorMessage = function assertTypeErrorMessage(f, test) {
        assertErrorMessage(f, TypeError, test);
    };
}

if (typeof assertRangeErrorMessage === 'undefined') {
    var assertRangeErrorMessage = function assertRangeErrorMessage(f, test) {
        assertErrorMessage(f, RangeError, test);
    };
}
load(libdir + "asserts.js");

var LENGTH = 1024, SYMBOL_INDEX = 999;

var big = [];
for (var i = 0; i < LENGTH; i++)
    big[i] = (i === SYMBOL_INDEX ? Symbol.for("comet") : i);

var progress;
function copy(arr, big) {
    for (var i = 0; i < LENGTH; i++) {
        arr[i] = big[i];
        progress = i;
    }
}

for (var T of [Uint8Array, Uint8ClampedArray, Int16Array, Float32Array]) {
    // Typed array constructors convert symbols using ToNumber, which throws.
    assertThrowsInstanceOf(() => new T(big), TypeError);

    // Element assignment does the same.
    var arr = new T(big.length);
    for (var k = 0; k < 3; k++) {
        progress = -1;
        assertThrowsInstanceOf(() => copy(arr, big), TypeError);
        assertEq(progress, SYMBOL_INDEX - 1);
        assertEq(arr[SYMBOL_INDEX], 0);
    }
}

vs

load(libdir + "asserts.js");

var LENGTH = 1024, SYMBOL_INDEX = 999;

var big = [];

for (let i = 0;i < LENGTH;i++) big[i] = i === SYMBOL_INDEX ? Symbol.for("comet") : i;

var progress;

function copy(arr, big) {
    for (let i = 0;i < LENGTH;i++) {
        arr[i] = big[i];

        progress = i;
    }
}

for (T of [Uint8Array, Uint8ClampedArray, Int16Array, Float32Array,]) {
    assertThrowsInstanceOf(()  => new T(big), TypeError);

    var arr = new T(big.length);

    for (let k = 0;k < 3;k++) {
        progress = -1;

        assertThrowsInstanceOf(()  => copy(arr, big), TypeError);

        assertEq(progress, SYMBOL_INDEX - 1);

        assertEq(arr[SYMBOL_INDEX], 0);
    }
}
// for-of on an Array consults the prototype chain when it encounters a hole.

load(libdir + "iteration.js");

var m = {1: 'peek'};
var a = [0, , 2, 3];
a.__proto__ = m;
var log = [];
Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
for (var x of a)
    log.push(x);
assertEq(log[1], 'peek');
assertEq(log.join(), "0,peek,2,3");

vs

load(libdir + "iteration.js");

var m = ({
    1: 'peek',
});

var a = [0,, 2, 3,];

a.__proto__ = m;

var log = [];

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

for (x of a) log.push(x);

assertEq(log[1], 'peek');

assertEq(log.join(), "0,peek,2,3");
// for-of visits each hole in an array full of holes.

var n = 0;
for (var x of Array(5)) {
    assertEq(x, undefined);
    n++;
}
assertEq(n, 5);

vs

var n = 0;

for (x of Array(5)) {
    assertEq(x, undefined);

    n++;
}

assertEq(n, 5);
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const ASM_TYPE_FAIL_STRING = "asm.js type error:";
const ASM_DIRECTIVE_FAIL_STRING = "\"use asm\" is only meaningful in the Directive Prologue of a function body";

const USE_ASM = '"use asm";';
const HEAP_IMPORTS = "const i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);"+
                     "const i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);"+
                     "const i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);"+
                     "const f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";
const BUF_MIN = 64 * 1024;
const BUF_CHANGE_MIN = 16 * 1024 * 1024;
const BUF_64KB = new ArrayBuffer(BUF_MIN);

function asmCompile()
{
    var f = Function.apply(null, arguments);
    assertEq(!isAsmJSCompilationAvailable() || isAsmJSModule(f), true);
    return f;
}

function asmCompileCached()
{
    if (!isAsmJSCompilationAvailable())
        return Function.apply(null, arguments);

    if (!isCachingEnabled()) {
        var f = Function.apply(null, arguments);
        assertEq(isAsmJSModule(f), true);
        return f;
    }

    var quotedArgs = [];
    for (var i = 0; i < arguments.length; i++)
        quotedArgs.push("'" + arguments[i] + "'");
    var code = "setCachingEnabled(true); var f = new Function(" + quotedArgs.join(',') + ");assertEq(isAsmJSModule(f), true);";
    nestedShell("--js-cache", "--no-js-cache-per-process", "--execute=" + code);

    var f = Function.apply(null, arguments);
    assertEq(isAsmJSModuleLoadedFromCache(f), true);
    return f;
}

function assertAsmDirectiveFail(str)
{
    if (!isAsmJSCompilationAvailable())
        return;

    // Turn on warnings-as-errors
    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);

    // Verify an error is thrown
    var caught = false;
    try {
        eval(str);
    } catch (e) {
        if ((''+e).indexOf(ASM_DIRECTIVE_FAIL_STRING) == -1)
            throw new Error("Didn't catch the expected directive failure error; instead caught: " + e + "\nStack: " + new Error().stack);
        caught = true;
    }
    if (!caught)
        throw new Error("Didn't catch the directive failure error");

    // Turn warnings-as-errors back off
    options("werror");
}

function assertAsmTypeFail()
{
    if (!isAsmJSCompilationAvailable())
        return;

    // Verify no error is thrown with warnings off
    Function.apply(null, arguments);

    // Turn on throwing on validation errors
    var oldOpts = options("throw_on_asmjs_validation_failure");
    assertEq(oldOpts.indexOf("throw_on_asmjs_validation_failure"), -1);

    // Verify an error is thrown
    var caught = false;
    try {
        Function.apply(null, arguments);
    } catch (e) {
        if ((''+e).indexOf(ASM_TYPE_FAIL_STRING) == -1)
            throw new Error("Didn't catch the expected type failure error; instead caught: " + e + "\nStack: " + new Error().stack);
        caught = true;
    }
    if (!caught)
        throw new Error("Didn't catch the type failure error");

    // Turn warnings-as-errors back off
    options("throw_on_asmjs_validation_failure");
}

function assertAsmLinkFail(f)
{
    if (!isAsmJSCompilationAvailable())
        return;

    assertEq(isAsmJSModule(f), true);

    // Verify no error is thrown with warnings off
    var ret = f.apply(null, Array.slice(arguments, 1));

    assertEq(isAsmJSFunction(ret), false);
    if (typeof ret === 'object')
        for (var i in ret)
            assertEq(isAsmJSFunction(ret[i]), false);

    // Turn on warnings-as-errors
    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);

    // Verify an error is thrown
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        // Arbitrary code an run in the GetProperty, so don't assert any
        // particular string
        caught = true;
    }
    if (!caught)
        throw new Error("Didn't catch the link failure error");

    // Turn warnings-as-errors back off
    options("werror");
}

// Linking should throw an exception even without warnings-as-errors
function assertAsmLinkAlwaysFail(f)
{
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        caught = true;
    }
    if (!caught)
        throw new Error("Didn't catch the link failure error");

    // Turn on warnings-as-errors
    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);

    // Verify an error is thrown
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        caught = true;
    }
    if (!caught)
        throw new Error("Didn't catch the link failure error");

    // Turn warnings-as-errors back off
    options("werror");
}

function assertAsmLinkDeprecated(f)
{
    if (!isAsmJSCompilationAvailable())
        return;

    // Verify no error is thrown with warnings off
    f.apply(null, Array.slice(arguments, 1));

    // Turn on warnings-as-errors
    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);

    // Verify an error is thrown
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        // Arbitrary code an run in the GetProperty, so don't assert any
        // particular string
        caught = true;
    }
    if (!caught)
        throw new Error("Didn't catch the link failure error");

    // Turn warnings-as-errors back off
    options("werror");
}

// Linking should throw a warning-as-error but otherwise run fine
function asmLink(f)
{
    if (!isAsmJSCompilationAvailable())
        return f.apply(null, Array.slice(arguments, 1));

    // Turn on warnings-as-errors
    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);

    var ret = f.apply(null, Array.slice(arguments, 1));

    // Turn warnings-as-errors back off
    options("werror");

    return ret;
}

vs

const ASM_TYPE_FAIL_STRING = "asm.js type error:";

const ASM_DIRECTIVE_FAIL_STRING = "\"use asm\" is only meaningful in the Directive Prologue of a function body";

const USE_ASM = '"use asm";';

const HEAP_IMPORTS = "const i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);" + "const i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);" + "const i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);" + "const f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";

const BUF_MIN = 64 * 1024;

const BUF_CHANGE_MIN = 16 * 1024 * 1024;

const BUF_64KB = new ArrayBuffer(BUF_MIN);

function asmCompile() {
    var f = Function.apply(null, arguments);
    assertEq(!isAsmJSCompilationAvailable() || isAsmJSModule(f), true);
    return f;
}

function asmCompileCached() {
    if (!isAsmJSCompilationAvailable()) return Function.apply(null, arguments);

    if (!isCachingEnabled()) {
        var f = Function.apply(null, arguments);

        assertEq(isAsmJSModule(f), true);

        return f;
    }
    var quotedArgs = [];
    for (let i = 0;i < arguments.length;i++) quotedArgs.push("'" + arguments[i] + "'");
    var code = "setCachingEnabled(true); var f = new Function(" + quotedArgs.join(',') + ");assertEq(isAsmJSModule(f), true);";
    nestedShell("--js-cache", "--no-js-cache-per-process", "--execute=" + code);
    var f = Function.apply(null, arguments);
    assertEq(isAsmJSModuleLoadedFromCache(f), true);
    return f;
}

function assertAsmDirectiveFail(str) {
    if (!isAsmJSCompilationAvailable()) return;

    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);
    var caught = false;
    try {
        eval(str);
    } catch (e) {
        if ('' + e.indexOf(ASM_DIRECTIVE_FAIL_STRING) == -1) throw new Error("Didn't catch the expected directive failure error; instead caught: " + e + "\nStack: " + new Error().stack);


        caught = true;
    }
    if (!caught) throw new Error("Didn't catch the directive failure error");

    options("werror");
}

function assertAsmTypeFail() {
    if (!isAsmJSCompilationAvailable()) return;

    Function.apply(null, arguments);
    var oldOpts = options("throw_on_asmjs_validation_failure");
    assertEq(oldOpts.indexOf("throw_on_asmjs_validation_failure"), -1);
    var caught = false;
    try {
        Function.apply(null, arguments);
    } catch (e) {
        if ('' + e.indexOf(ASM_TYPE_FAIL_STRING) == -1) throw new Error("Didn't catch the expected type failure error; instead caught: " + e + "\nStack: " + new Error().stack);


        caught = true;
    }
    if (!caught) throw new Error("Didn't catch the type failure error");

    options("throw_on_asmjs_validation_failure");
}

function assertAsmLinkFail(f) {
    if (!isAsmJSCompilationAvailable()) return;

    assertEq(isAsmJSModule(f), true);
    var ret = f.apply(null, Array.slice(arguments, 1));
    assertEq(isAsmJSFunction(ret), false);
    if (typeof ret === 'object') for (i in ret) assertEq(isAsmJSFunction(ret[i]), false);

    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        caught = true;
    }
    if (!caught) throw new Error("Didn't catch the link failure error");

    options("werror");
}

function assertAsmLinkAlwaysFail(f) {
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        caught = true;
    }
    if (!caught) throw new Error("Didn't catch the link failure error");

    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        caught = true;
    }
    if (!caught) throw new Error("Didn't catch the link failure error");

    options("werror");
}

function assertAsmLinkDeprecated(f) {
    if (!isAsmJSCompilationAvailable()) return;

    f.apply(null, Array.slice(arguments, 1));
    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);
    var caught = false;
    try {
        f.apply(null, Array.slice(arguments, 1));
    } catch (e) {
        caught = true;
    }
    if (!caught) throw new Error("Didn't catch the link failure error");

    options("werror");
}

function asmLink(f) {
    if (!isAsmJSCompilationAvailable()) return f.apply(null, Array.slice(arguments, 1));

    var oldOpts = options("werror");
    assertEq(oldOpts.indexOf("werror"), -1);
    var ret = f.apply(null, Array.slice(arguments, 1));
    options("werror");
    return ret;
}
// Replacing Array.prototype.iterator with something non-callable makes for-of throw.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

function test(v) {
    Array.prototype[Symbol.iterator] = v;
    assertThrowsInstanceOf(function () { for (var x of []) ; }, TypeError);
}
test(undefined);
test(null);
test({});

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

function test(v) {
    Array.prototype[Symbol.iterator] = v;
    assertThrowsInstanceOf(function() {
        for (x of []) ;
    }, TypeError);
}

test(undefined);

test(null);

test(({}));
var called = false;
var a = [/* hole */, undefined, {
    toString() {
        if (!called) {
            called = true;
            a.length = 3;
            Object.defineProperty(a, "length", {writable:false});
        }
        return 0;
    }
}, 0];
a.sort();

assertEq(a.length, 3);
assertEq(a[1], 0);
assertEq(a[2], undefined);

vs

var called = false;

var a = [, undefined, ({
    toString: (function() {
        if (!called) {
            called = true;

            a.length = 3;

            Object.defineProperty(a, "length", {
                writable: false,
            });
        }
        return 0;
    }),
}), 0,];

a.sort();

assertEq(a.length, 3);

assertEq(a[1], 0);

assertEq(a[2], undefined);
// Control can exit a for-of loop via throw.

function f() {
    for (var a of [1, 2, 3]) {
        for (var b of [1, 2, 3]) {
            for (var c of [1, 2, 3]) {
                if (a !== b && b !== c && c !== a)
                    throw [a, b, c];
            }
        }
    }
}

var x = null;
try {
    f();
} catch (exc) {
    x = exc.join("");
}
assertEq(x, "123");

vs

function f() {
    for (a of [1, 2, 3,]) {
        for (b of [1, 2, 3,]) {
            for (c of [1, 2, 3,]) {
                if (a !== b && b !== c && c !== a) throw [a, b, c,];

            }
        }
    }
}

var x = null;

try {
    f();
} catch (exc) {
    x = exc.join("");
}

assertEq(x, "123");
setJitCompilerOption("ion.warmup.trigger", 40);

const constructors = [
    Int8Array,
    Uint8Array,
    Uint8ClampedArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Float32Array,
    Float64Array ];

// Ensure that when creating TypedArrays under JIT
// the sort() method works as expected (bug 1295034).
for (var ctor of constructors) {
  for (var _ of Array(1024)) {
    var testArray = new ctor(10);
    testArray.sort();
  }
}

if (typeof reportCompare === "function")
    reportCompare(true, true);

vs

setJitCompilerOption("ion.warmup.trigger", 40);

const constructors = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array,];

for (ctor of constructors) {
    for (_ of Array(1024)) {
        var testArray = new ctor(10);

        testArray.sort();
    }
}

if (typeof reportCompare === "function") reportCompare(true, true);

// for-of can iterate arguments objects for other active frames.

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;
function g(obj) {
    for (var v of obj)
        s += v;
}

function f() {
    g(arguments);
}

s = '';
f(1, 2, 3);
assertEq(s, '123');

vs

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;

function g(obj) {
    for (v of obj) s += v;
}

function f() {
    g(arguments);
}

s = '';

f(1, 2, 3);

assertEq(s, '123');
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

var set = new Set();
set.add(set);

var magic = deserialize(serialize(set));
assertEq(magic.size, 1);
assertEq(magic.values().next().value, magic);

var values = [
    "a", "\uDEFF", undefined, null, -3.5, true, false, NaN, 155, -2
]

set = new Set();
for (var value of values) {
    set.add(value)
}

magic = deserialize(serialize(set));
var i = 0;
for (value of magic) {
    assertEq(value, values[i++]);
}

assertEq([...set.keys()].toSource(), [...magic.keys()].toSource());
assertEq([...set.values()].toSource(), [...magic.values()].toSource());

var obj = {a: 1};
obj.set = new Set();
obj.set.add(obj);

magic = deserialize(serialize(obj));

assertEq(magic.set.values().next().value, magic);
assertEq(magic.a, 1);

set = new Set();
set.add(new Number(1));
set.add(new String("aaaa"));
set.add(new Date(NaN));

magic = deserialize(serialize(set));

values = magic.values();
assertEq(values.next().value.valueOf(), 1);
assertEq(values.next().value.valueOf(), "aaaa");
assertEq(values.next().value.valueOf(), NaN);
assertEq(values.next().done, true);

// Make sure expandos aren't cloned (Bug 1041172)
set = new Set();
set.a = "aaaaa";
magic = deserialize(serialize(set));
assertEq("a" in magic, false);
assertEq(Object.keys(magic).length, 0);

// Busted [[Prototype]] shouldn't matter
set = new Set();
Object.setPrototypeOf(set, null);
Set.prototype.add.call(set, "aaa");
magic = deserialize(serialize(set));
assertEq(magic.has("aaa"), true);
assertEq(magic.size, 1);

// Can't fuzz around with Set after it is cloned
obj = {
    a: new Set(),
    get b() {
        obj.a.delete("test");
        return "invoked";
    }
}
obj.a.add("test");
assertEq(obj.a.has("test"), true);
magic = deserialize(serialize(obj));
assertEq(obj.a.has("test"), false);
assertEq(magic.a.size, 1);
assertEq([...magic.a.keys()].toString(), "test");
assertEq(magic.b, "invoked");

vs

var set = new Set();

set.add(set);

var magic = deserialize(serialize(set));

assertEq(magic.size, 1);

assertEq(magic.values().next().value, magic);

var values = ["a", "\uDEFF", undefined, null, -3.5, true, false, NaN, 155, -2,];

set = new Set();

for (value of values) {
    set.add(value);
}

magic = deserialize(serialize(set));

var i = 0;

for (value of magic) {
    assertEq(value, values[i++]);
}

assertEq([...set.keys(),].toSource(), [...magic.keys(),].toSource());

assertEq([...set.values(),].toSource(), [...magic.values(),].toSource());

var obj = ({
    a: 1,
});

obj.set = new Set();

obj.set.add(obj);

magic = deserialize(serialize(obj));

assertEq(magic.set.values().next().value, magic);

assertEq(magic.a, 1);

set = new Set();

set.add(new Number(1));

set.add(new String("aaaa"));

set.add(new Date(NaN));

magic = deserialize(serialize(set));

values = magic.values();

assertEq(values.next().value.valueOf(), 1);

assertEq(values.next().value.valueOf(), "aaaa");

assertEq(values.next().value.valueOf(), NaN);

assertEq(values.next().done, true);

set = new Set();

set.a = "aaaaa";

magic = deserialize(serialize(set));

assertEq("a" in magic, false);

assertEq(Object.keys(magic).length, 0);

set = new Set();

Object.setPrototypeOf(set, null);

Set.prototype.add.call(set, "aaa");

magic = deserialize(serialize(set));

assertEq(magic.has("aaa"), true);

assertEq(magic.size, 1);

obj = ({
    a: new Set(),
    get b() {
        obj.a.delete("test");
        return "invoked";
    },
});

obj.a.add("test");

assertEq(obj.a.has("test"), true);

magic = deserialize(serialize(obj));

assertEq(obj.a.has("test"), false);

assertEq(magic.a.size, 1);

assertEq([...magic.a.keys(),].toString(), "test");

assertEq(magic.b, "invoked");
// Basic for-of test with Proxy whose iterator method is a generator.

var arr = ['a', 'b', 'c', 'd'];
var proxy = new Proxy(arr, {
    get(target, property, receiver) {
        if (property === Symbol.iterator) {
            return function* () {
                for (var i = 0; i < arr.length; i++)
                    yield arr[i];
            }
        }

        return Reflect.get(target, property, receiver);
    }
});

for (var i = 0; i < 2; i++)
    assertEq([...proxy].join(","), "a,b,c,d");

vs

var arr = ['a', 'b', 'c', 'd',];

var proxy = new Proxy(arr, ({
    get: (function(target, property, receiver) {
        if (property === Symbol.iterator) {
            return function*() {
                for (let i = 0;i < arr.length;i++) yield arr[i];
            };
        }
        return Reflect.get(target, property, receiver);
    }),
}));

for (let i = 0;i < 2;i++) assertEq([...proxy,].join(","), "a,b,c,d");
// |jit-test| error:dead object

var P = newGlobal().eval(`
(class extends Promise {
    static resolve(o) {
        return o;
    }
});
`);

Promise.all.call(P, [{
    then(r) {
        nukeAllCCWs();
        r();
    }
}]);

vs

var P = newGlobal().eval(`
(class extends Promise {
    static resolve(o) {
        return o;
    }
});
`);

Promise.all.call(P, [({
    then: (function(r) {
        nukeAllCCWs();
        r();
    }),
}),]);
if (!wasmIsSupported())
    quit();

load(libdir + "asserts.js");

function wasmEvalText(str, imports) {
    let binary = wasmTextToBinary(str);
    let valid = WebAssembly.validate(binary);

    let m;
    try {
        m = new WebAssembly.Module(binary);
        assertEq(valid, true);
    } catch(e) {
        if (!e.toString().match(/out of memory/))
            assertEq(valid, false);
        throw e;
    }

    return new WebAssembly.Instance(m, imports);
}

function wasmValidateText(str) {
    assertEq(WebAssembly.validate(wasmTextToBinary(str)), true);
}

function wasmFailValidateText(str, pattern) {
    let binary = wasmTextToBinary(str);
    assertEq(WebAssembly.validate(binary), false);
    assertErrorMessage(() => new WebAssembly.Module(binary), WebAssembly.CompileError, pattern);
}

function mismatchError(actual, expect) {
    var str = `type mismatch: expression has type ${actual} but expected ${expect}`;
    return RegExp(str);
}

const emptyStackError = /from empty stack/;
const unusedValuesError = /unused values not explicitly dropped by end of block/;

function jsify(wasmVal) {
    if (wasmVal === 'nan')
        return NaN;
    if (wasmVal === 'infinity')
        return Infinity;
    if (wasmVal === '-infinity')
        return Infinity;
    if (wasmVal === '-0')
        return -0;
    return wasmVal;
}

function _augmentSrc(src, assertions) {
    let i = 0;
    let newSrc = src.substr(0, src.lastIndexOf(')'));
    for (let { func, args, expected, type } of assertions) {
        newSrc += `
        (func (export "assert_${i++}") (result i32)
         ${ args ? args.join('\n') : '' }
         call ${func}`;

        if (typeof expected !== 'undefined') {
            switch (type) {
                case 'f32':
                    newSrc += `
         i32.reinterpret/f32
         i32.const ${expected}
         i32.eq`;
                    break;
                case 'f64':
                    newSrc += `
         i64.reinterpret/f64
         i64.const ${expected}
         i64.eq`;
                    break;
                case 'i64':
                    newSrc += `
         i64.const ${expected}
         i64.eq`;
                    break;
                default:
                    throw new Error("unexpected usage of wasmAssert");
            }
        } else {
            // Always true when there's no expected return value.
            newSrc += "\ni32.const 1";
        }

        newSrc += ')\n';
    }
    newSrc += ')';
    return newSrc;
}

function wasmAssert(src, assertions, maybeImports = {}) {
    let { exports } = wasmEvalText(_augmentSrc(src, assertions), maybeImports);
    for (let i = 0; i < assertions.length; i++) {
        let { func, expected, params } = assertions[i];
        let paramText = params ? params.join(', ') : '';
        assertEq(exports[`assert_${i}`](), 1,
                 `Unexpected value when running ${func}(${paramText}), expecting ${expected}.`);
    }
}

// Fully test a module:
// - ensure it validates.
// - ensure it compiles and produces the expected result.
// - ensure textToBinary(binaryToText(binary)) = binary
// Preconditions:
// - the binary module must export a function called "run".
function wasmFullPass(text, expected, maybeImports, ...args) {
    let binary = wasmTextToBinary(text);
    assertEq(WebAssembly.validate(binary), true, "Must validate.");

    let module = new WebAssembly.Module(binary);
    let instance = new WebAssembly.Instance(module, maybeImports);
    assertEq(typeof instance.exports.run, 'function', "A 'run' function must be exported.");
    assertEq(instance.exports.run(...args), expected, "Initial module must return the expected result.");
}

// Ditto, but expects a function named '$run' instead of exported with this name.
function wasmFullPassI64(text, expected, maybeImports, ...args) {
    let binary = wasmTextToBinary(text);
    assertEq(WebAssembly.validate(binary), true, "Must validate.");

    let augmentedSrc = _augmentSrc(text, [ { type: 'i64', func: '$run', args, expected } ]);
    let augmentedBinary = wasmTextToBinary(augmentedSrc);
    new WebAssembly.Instance(new WebAssembly.Module(augmentedBinary), maybeImports).exports.assert_0();
}

function wasmRunWithDebugger(wast, lib, init, done) {
    let g = newGlobal('');
    let dbg = new Debugger(g);

    g.eval(`
var wasm = wasmTextToBinary('${wast}');
var lib = ${lib || 'undefined'};
var m = new WebAssembly.Instance(new WebAssembly.Module(wasm), lib);`);

    var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];

    init({dbg, wasmScript, g,});
    let result = undefined, error = undefined;
    try {
        result = g.eval("m.exports.test()");
    } catch (ex) {
        error = ex;
    }
    done({dbg, result, error, wasmScript, g,});
}

const WasmHelpers = {};

(function() {
    let enabled = false;
    try {
        enableSingleStepProfiling();
        disableSingleStepProfiling();
        enabled = true;
    } catch (e) {}
    WasmHelpers.isSingleStepProfilingEnabled = enabled;
})();

WasmHelpers._normalizeStack = (stack, preciseStacks) => {
    var wasmFrameTypes = [
        {re:/^jit call to int64 wasm function$/,                          sub:"i64>"},
        {re:/^out-of-line coercion for jit entry arguments \(in wasm\)$/, sub:"ool>"},
        {re:/^wasm-function\[(\d+)\] \(.*\)$/,                            sub:"$1"},
        {re:/^(fast|slow) exit trampoline (to native )?\(in wasm\)$/,     sub:"<"},
        {re:/^call to[ asm.js]? native (.*) \(in wasm\)$/,                sub:"$1"},
        {re:/ \(in wasm\)$/,                                              sub:""}
    ];

    let entryRegexps;
    if (preciseStacks) {
        entryRegexps = [
            {re:/^slow entry trampoline \(in wasm\)$/,                    sub:"!>"},
            {re:/^fast entry trampoline \(in wasm\)$/,                    sub:">"},
        ];
    } else {
        entryRegexps = [
            {re:/^(fast|slow) entry trampoline \(in wasm\)$/,             sub:">"}
        ];
    }
    wasmFrameTypes = entryRegexps.concat(wasmFrameTypes);

    var framesIn = stack.split(',');
    var framesOut = [];
    for (let frame of framesIn) {
        for (let {re, sub} of wasmFrameTypes) {
            if (re.test(frame)) {
                framesOut.push(frame.replace(re, sub));
                break;
            }
        }
    }

    return framesOut.join(',');
};

WasmHelpers._removeAdjacentDuplicates = array => {
    if (array.length < 2)
        return;
    let i = 0;
    for (let j = 1; j < array.length; j++) {
        if (array[i] !== array[j])
            array[++i] = array[j];
    }
    array.length = i + 1;
}

WasmHelpers.normalizeStacks = (stacks, preciseStacks = false) => {
    let observed = [];
    for (let i = 0; i < stacks.length; i++)
        observed[i] = WasmHelpers._normalizeStack(stacks[i], preciseStacks);
    WasmHelpers._removeAdjacentDuplicates(observed);
    return observed;
};

WasmHelpers._compareStacks = (got, expect) => {
    if (got.length != expect.length) {
        return false;
    }
    for (let i = 0; i < got.length; i++) {
        if (got[i] !== expect[i])
            return false;
    }
    return true;
}

WasmHelpers.assertEqImpreciseStacks = (got, expect) => {
    let observed = WasmHelpers.normalizeStacks(got, /* precise */ false);
    let same = WasmHelpers._compareStacks(observed, expect);
    if (!same) {
        if (observed.length != expect.length) {
            print(`Got:\n${observed.toSource()}\nExpect:\n${expect.toSource()}`);
            assertEq(observed.length, expect.length);
        }
        for (let i = 0; i < observed.length; i++) {
            if (observed[i] !== expect[i]) {
                print(`On stack ${i}, Got:\n${observed[i]}\nExpect:\n${expect[i]}`);
                assertEq(observed[i], expect[i]);
            }
        }
    }
}

WasmHelpers.extractStackFrameFunction = (frameString) => {
    var [_, name, filename, line, column] = frameString.match(/^(.*)@(.*):(.*):(.*)$/);
    if (name)
        return name;
    if (/wasm-function/.test(line))
        return line;
    return "";
};

WasmHelpers.assertStackTrace = (exception, expected) => {
    let callsites = exception.stack.trim().split('\n').map(WasmHelpers.extractStackFrameFunction);
    assertEq(callsites.length, expected.length);
    for (let i = 0; i < callsites.length; i++) {
        assertEq(callsites[i], expected[i]);
    }
};

WasmHelpers.nextLineNumber = (n=1) => {
    return +(new Error().stack).split('\n')[1].split(':')[1] + n;
}

WasmHelpers.startProfiling = () => {
    if (!WasmHelpers.isSingleStepProfilingEnabled)
        return;
    enableSingleStepProfiling();
}

WasmHelpers.endProfiling = () => {
    if (!WasmHelpers.isSingleStepProfilingEnabled)
        return;
    return disableSingleStepProfiling();
}

WasmHelpers.assertEqPreciseStacks = (observed, expectedStacks) => {
    if (!WasmHelpers.isSingleStepProfilingEnabled)
        return null;

    observed = WasmHelpers.normalizeStacks(observed, /* precise */ true);

    for (let i = 0; i < expectedStacks.length; i++) {
        if (WasmHelpers._compareStacks(observed, expectedStacks[i]))
            return i;
    }

    throw new Error(`no plausible stacks found, observed: ${observed.join('/')}
Expected one of:
${expectedStacks.map(stacks => stacks.join("/")).join('\n')}`);
}

vs

if (!wasmIsSupported()) quit();


load(libdir + "asserts.js");

function wasmEvalText(str, imports) {
    let binary = wasmTextToBinary(str);
    let valid = WebAssembly.validate(binary);
    let m;
    try {
        m = new WebAssembly.Module(binary);

        assertEq(valid, true);
    } catch (e) {
        if (!e.toString().match(/out of memory/)) assertEq(valid, false);


        throw e;
    }
    return new WebAssembly.Instance(m, imports);
}

function wasmValidateText(str) {
    assertEq(WebAssembly.validate(wasmTextToBinary(str)), true);
}

function wasmFailValidateText(str, pattern) {
    let binary = wasmTextToBinary(str);
    assertEq(WebAssembly.validate(binary), false);
    assertErrorMessage(()  => new WebAssembly.Module(binary), WebAssembly.CompileError, pattern);
}

function mismatchError(actual, expect) {
    var str = `type mismatch: expression has type ${actual} but expected {expect}`;
    return RegExp(str);
}

const emptyStackError = /from empty stack/;

const unusedValuesError = /unused values not explicitly dropped by end of block/;

function jsify(wasmVal) {
    if (wasmVal === 'nan') return NaN;

    if (wasmVal === 'infinity') return Infinity;

    if (wasmVal === '-infinity') return Infinity;

    if (wasmVal === '-0') return -0;

    return wasmVal;
}

function _augmentSrc(src, assertions) {
    let i = 0;
    let newSrc = src.substr(0, src.lastIndexOf(')'));
    for ({func, args, expected, type,    } of assertions) {
        newSrc += `
        (func (export "assert_${i++}") (result i32)
         {args ? args.join('\n') : ''}
         call {func}`;

        if (typeof expected !== 'undefined') {
            switch (type) {
                case 'f32':
                    newSrc += `
         i32.reinterpret/f32
         i32.const ${expected}
         i32.eq`;

                break;

                case 'f64':
                    newSrc += `
         i64.reinterpret/f64
         i64.const ${expected}
         i64.eq`;

                break;

                case 'i64':
                    newSrc += `
         i64.const ${expected}
         i64.eq`;

                break;

                default:
                    throw new Error("unexpected usage of wasmAssert");

            }
        } else {
            newSrc += "\ni32.const 1";
        }

        newSrc += ')\n';
    }
    newSrc += ')';
    return newSrc;
}

function wasmAssert(src, assertions, maybeImports = {}) {
    let {exports,    } = wasmEvalText(_augmentSrc(src, assertions), maybeImports);
    for (let i = 0;i < assertions.length;i++) {
        let {func, expected, params,        } = assertions[i];

        let paramText = params ? params.join(', ') : '';

        assertEq(exports[`assert_${i}`](), 1, `Unexpected value when running ${func}({paramText}), expecting {expected}.`);
    }
}

function wasmFullPass(text, expected, maybeImports, args) {
    let binary = wasmTextToBinary(text);
    assertEq(WebAssembly.validate(binary), true, "Must validate.");
    let module = new WebAssembly.Module(binary);
    let instance = new WebAssembly.Instance(module, maybeImports);
    assertEq(typeof instance.exports.run, 'function', "A 'run' function must be exported.");
    assertEq(instance.exports.run(...args), expected, "Initial module must return the expected result.");
}

function wasmFullPassI64(text, expected, maybeImports, args) {
    let binary = wasmTextToBinary(text);
    assertEq(WebAssembly.validate(binary), true, "Must validate.");
    let augmentedSrc = _augmentSrc(text, [{
        type: 'i64',
        func: '$run',
        args,
        expected,
    },]);
    let augmentedBinary = wasmTextToBinary(augmentedSrc);
    new WebAssembly.Instance(new WebAssembly.Module(augmentedBinary), maybeImports).exports.assert_0();
}

function wasmRunWithDebugger(wast, lib, init, done) {
    let g = newGlobal('');
    let dbg = new Debugger(g);
    g.eval(`
var wasm = wasmTextToBinary('${wast}');
var lib = {lib || 'undefined'};
var m = new WebAssembly.Instance(new WebAssembly.Module(wasm), lib);`);
    var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
    init({
        dbg,
        wasmScript,
        g,
    });
    let result = undefined, error = undefined;
    try {
        result = g.eval("m.exports.test()");
    } catch (ex) {
        error = ex;
    }
    done({
        dbg,
        result,
        error,
        wasmScript,
        g,
    });
}

const WasmHelpers = ({});

(function() {
    let enabled = false;
    try {
        enableSingleStepProfiling();

        disableSingleStepProfiling();

        enabled = true;
    } catch (e) { 
        
    }
    WasmHelpers.isSingleStepProfilingEnabled = enabled;
})();

WasmHelpers._normalizeStack = (stack, preciseStacks)  => {
    var wasmFrameTypes = [{
        re: /^jit call to int64 wasm function$/,
        sub: "i64>",
    }, {
        re: /^out-of-line coercion for jit entry arguments \(in wasm\)$/,
        sub: "ool>",
    }, {
        re: /^wasm-function\[(\d+)\] \(.*\)$/,
        sub: "$1",
    }, {
        re: /^(fast|slow) exit trampoline (to native )?\(in wasm\)$/,
        sub: "<",
    }, {
        re: /^call to[ asm.js]? native (.*) \(in wasm\)$/,
        sub: "$1",
    }, {
        re: / \(in wasm\)$/,
        sub: "",
    },];
    let entryRegexps;
    if (preciseStacks) {
        entryRegexps = [{
            re: /^slow entry trampoline \(in wasm\)$/,
            sub: "!>",
        }, {
            re: /^fast entry trampoline \(in wasm\)$/,
            sub: ">",
        },];
    } else {
        entryRegexps = [{
            re: /^(fast|slow) entry trampoline \(in wasm\)$/,
            sub: ">",
        },];
    }
    wasmFrameTypes = entryRegexps.concat(wasmFrameTypes);
    var framesIn = stack.split(',');
    var framesOut = [];
    for (frame of framesIn) {
        for ({re, sub,        } of wasmFrameTypes) {
            if (re.test(frame)) {
                framesOut.push(frame.replace(re, sub));

                break;
            }
        }
    }
    return framesOut.join(',');
};

WasmHelpers._removeAdjacentDuplicates = array => {
    if (array.length < 2) return;

    let i = 0;
    for (let j = 1;j < array.length;j++) {
        if (array[i] !== array[j]) array[++i] = array[j];

    }
    array.length = i + 1;
};

WasmHelpers.normalizeStacks = (stacks, preciseStacks = false)  => {
    let observed = [];
    for (let i = 0;i < stacks.length;i++) observed[i] = WasmHelpers._normalizeStack(stacks[i], preciseStacks);
    WasmHelpers._removeAdjacentDuplicates(observed);
    return observed;
};

WasmHelpers._compareStacks = (got, expect)  => {
    if (got.length != expect.length) {
        return false;
    }
    for (let i = 0;i < got.length;i++) {
        if (got[i] !== expect[i]) return false;

    }
    return true;
};

WasmHelpers.assertEqImpreciseStacks = (got, expect)  => {
    let observed = WasmHelpers.normalizeStacks(got, false);
    let same = WasmHelpers._compareStacks(observed, expect);
    if (!same) {
        if (observed.length != expect.length) {
            print(`Got:\n${observed.toSource()}\nExpect:\n{expect.toSource()}`);

            assertEq(observed.length, expect.length);
        }

        for (let i = 0;i < observed.length;i++) {
            if (observed[i] !== expect[i]) {
                print(`On stack ${i}, Got:\n{observed[i]}\nExpect:\n{expect[i]}`);

                assertEq(observed[i], expect[i]);
            }
        }
    }
};

WasmHelpers.extractStackFrameFunction = frameString => {
    var [_,name,filename,line,column,] = frameString.match(/^(.*)@(.*):(.*):(.*)$/);
    if (name) return name;

    if (/wasm-function/.test(line)) return line;

    return "";
};

WasmHelpers.assertStackTrace = (exception, expected)  => {
    let callsites = exception.stack.trim().split('\n').map(WasmHelpers.extractStackFrameFunction);
    assertEq(callsites.length, expected.length);
    for (let i = 0;i < callsites.length;i++) {
        assertEq(callsites[i], expected[i]);
    }
};

WasmHelpers.nextLineNumber = n = 1 => {
    return +new Error().stack.split('\n')[1].split(':')[1] + n;
};

WasmHelpers.startProfiling = ()  => {
    if (!WasmHelpers.isSingleStepProfilingEnabled) return;

    enableSingleStepProfiling();
};

WasmHelpers.endProfiling = ()  => {
    if (!WasmHelpers.isSingleStepProfilingEnabled) return;

    return disableSingleStepProfiling();
};

WasmHelpers.assertEqPreciseStacks = (observed, expectedStacks)  => {
    if (!WasmHelpers.isSingleStepProfilingEnabled) return null;

    observed = WasmHelpers.normalizeStacks(observed, true);
    for (let i = 0;i < expectedStacks.length;i++) {
        if (WasmHelpers._compareStacks(observed, expectedStacks[i])) return i;

    }
    throw new Error(`no plausible stacks found, observed: ${observed.join('/')}
Expected one of:
{expectedStacks.map(stacks => stacks.join("/")).join('\n')}`);
};
// Nested for-of loops on the same array get distinct iterators.

var a = [1, 2, 3];
var s = '';
for (var x of a)
    for (var y of a)
        s += '' + x + y + ',';
assertEq(s, '11,12,13,21,22,23,31,32,33,');

vs

var a = [1, 2, 3,];

var s = '';

for (x of a) for (y of a) s += '' + x + y + ',';

assertEq(s, '11,12,13,21,22,23,31,32,33,');
// An exception thrown from a proxy trap while getting the .iterator method is propagated.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

var p = new Proxy({}, {
    get(target, property) {
        if (property === Symbol.iterator)
            throw "fit";
        return undefined;
    }
});
assertThrowsValue(function () { for (var v of p) {} }, "fit");

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

var p = new Proxy(({}), ({
    get: (function(target, property) {
        if (property === Symbol.iterator) throw "fit";

        return undefined;
    }),
}));

assertThrowsValue((function() {
    for (v of p) { 
        
    }
}), "fit");
function test(fun) {
    fun();
}

// Generate a CallAnyScripted stub in test()
for (let i = 0; i < 20; i++) {
    test(function() { /* wheeee */ });
}

class foo {
    constructor() { }
}

// Compile foo()
for (let i = 0; i < 11; i++)
    new foo();

try {
    test(foo);
    throw new Error("Invoking a class constructor without new must throw");
} catch (e) {
    if (!(e instanceof TypeError))
        throw e;
}

vs

function test(fun) {
    fun();
}

for (let i = 0;i < 20;i++) {
    test(function() { });
}

class foo {

    constructor() { }
}

for (let i = 0;i < 11;i++) new foo();

try {
    test(foo);

    throw new Error("Invoking a class constructor without new must throw");
} catch (e) {
    if (!e instanceof TypeError) throw e;

}
function f(x) {
    for (var i = 0; i < 40; ++i) {
	var stack = getBacktrace({args: true});
	(function() { g = x;});
    }
}
f(1);

vs

function f(x) {
    for (let i = 0;i < 40;++i) {
        var stack = getBacktrace({
            args: true,
        });

        function() {
            g = x;
        };
    }
}

f(1);
// Array.keys() and .entries() on an empty array produce empty iterators

var arr = [];
var ki = arr.keys(), ei = arr.entries();
var p = Object.getPrototypeOf(ki);
assertEq(Object.getPrototypeOf(ei), p);

for (let k of ki)
  throw "FAIL";
for (let [k, v] of ei)
  throw "FAIL";

vs

var arr = [];

var ki = arr.keys(), ei = arr.entries();

var p = Object.getPrototypeOf(ki);

assertEq(Object.getPrototypeOf(ei), p);

for (k of ki) throw "FAIL";

for ([k,v,] of ei) throw "FAIL";
// A break statement leaves a for-of loop.

var log = '';
for (var x of ['a', 'b', 'c']) {
    log += x;
    if (x === 'b')
        break;
}
assertEq(log, "ab");

vs

var log = '';

for (x of ['a', 'b', 'c',]) {
    log += x;

    if (x === 'b') break;

}

assertEq(log, "ab");
// for-of works on strings and String objects.

load(libdir + "string.js");

function test(s, expectedCodePoints) {
    var copy = '';
    var codepoints = 0;
    var singleHighSurrogate = false;
    for (var v of s) {
        assertEq(typeof v, 'string');
        assertEq(v.length, isSurrogatePair(v) ? 2 : 1);
        assertEq(false, singleHighSurrogate && isLowSurrogate(v));
        copy += v;
        codepoints += 1;
        singleHighSurrogate = !isSurrogatePair(v) && isHighSurrogate(v);
    }
    assertEq(copy, String(s));
    assertEq(codepoints, expectedCodePoints);
}

test('', 0);
test('abc', 3);
test('a \0 \ufffe \ufeff', 7);

// Non-BMP characters are generally passed to JS in UTF-16, as surrogate pairs.
// ES6 requires that such pairs be treated as a single code point in for-of.
test('\ud808\udf45', 1);

// Also test invalid surrogate pairs:
// (1) High surrogate not followed by low surrogate
test('\ud808', 1);
test('\ud808\u0000', 2);
// (2) Low surrogate not preceded by high surrogate
test('\udf45', 1);
test('\u0000\udf45', 2);
// (3) Low surrogate followed by high surrogate
test('\udf45\ud808', 2);

test(new String(''), 0);
test(new String('abc'), 3);
test(new String('a \0 \ufffe \ufeff'), 7);
test(new String('\ud808\udf45'), 1);
test(new String('\ud808'), 1);
test(new String('\ud808\u0000'), 2);
test(new String('\udf45'), 1);
test(new String('\u0000\udf45'), 2);
test(new String('\udf45\ud808'), 2);

vs

load(libdir + "string.js");

function test(s, expectedCodePoints) {
    var copy = '';
    var codepoints = 0;
    var singleHighSurrogate = false;
    for (v of s) {
        assertEq(typeof v, 'string');

        assertEq(v.length, isSurrogatePair(v) ? 2 : 1);

        assertEq(false, singleHighSurrogate && isLowSurrogate(v));

        copy += v;

        codepoints += 1;

        singleHighSurrogate = !isSurrogatePair(v) && isHighSurrogate(v);
    }
    assertEq(copy, String(s));
    assertEq(codepoints, expectedCodePoints);
}

test('', 0);

test('abc', 3);

test('a \0 \ufffe \ufeff', 7);

test('\ud808\udf45', 1);

test('\ud808', 1);

test('\ud808\u0000', 2);

test('\udf45', 1);

test('\u0000\udf45', 2);

test('\udf45\ud808', 2);

test(new String(''), 0);

test(new String('abc'), 3);

test(new String('a \0 \ufffe \ufeff'), 7);

test(new String('\ud808\udf45'), 1);

test(new String('\ud808'), 1);

test(new String('\ud808\u0000'), 2);

test(new String('\udf45'), 1);

test(new String('\u0000\udf45'), 2);

test(new String('\udf45\ud808'), 2);
// for-of does not trigger the JS 1.7 for-in destructuring special case.

var data = [[1, 2, 3], [4, 5, 6, 7]];

function test(vars, expr, result) {
    var s = '';
    eval("for (" + vars + " of data) s += (" + expr + ") + ';';");
    assertEq(s, result);
}

for (var prefix of ["var ", "let ", ""]) {
    test(prefix + "[a, b, c]",
         "a + ',' + b + ',' + c",
         "1,2,3;4,5,6;");
}

test("var [a]", "a", "1;4;");
test("var {length: len}", "len", "3;4;");
test("var {length}", "length", "3;4;");
test("{}", "0", "0;0;");

vs

var data = [[1, 2, 3,], [4, 5, 6, 7,],];

function test(vars, expr, result) {
    var s = '';
    eval("for (" + vars + " of data) s += (" + expr + ") + ';';");
    assertEq(s, result);
}

for (prefix of ["var ", "let ", "",]) {
    test(prefix + "[a, b, c]", "a + ',' + b + ',' + c", "1,2,3;4,5,6;");
}

test("var [a]", "a", "1;4;");

test("var {length: len}", "len", "3;4;");

test("var {length}", "length", "3;4;");

test("{}", "0", "0;0;");
load(libdir + "asserts.js");

let foo = {};
for (let method of ["resolve", "reject", "race"]) {
  assertErrorMessage(
    () => Promise[method].call(foo),
    TypeError,
    "foo is not a constructor"
  );
  assertErrorMessage(
    () => Promise[method].call(foo, []),
    TypeError,
    "foo is not a constructor"
  );
  assertErrorMessage(
    () => Promise[method].call({}, [], foo),
    TypeError,
    "({}) is not a constructor"
  );
}

vs

load(libdir + "asserts.js");

let foo = ({});

for (method of ["resolve", "reject", "race",]) {
    assertErrorMessage(()  => Promise[method].call(foo), TypeError, "foo is not a constructor");

    assertErrorMessage(()  => Promise[method].call(foo, []), TypeError, "foo is not a constructor");

    assertErrorMessage(()  => Promise[method].call({    }, [], foo), TypeError, "({}) is not a constructor");
}
// for-of works with generators.

function* range(n) {
    for (var i = 0; i < n; i++)
        yield i;
}

var s = '';
for (var a of range(4))
    s += a;
assertEq(s, '0123');

vs

function *range(n) {
    for (let i = 0;i < n;i++) yield i;
}

var s = '';

for (a of range(4)) s += a;

assertEq(s, '0123');
// Don't assert if the wrapper that's the value of stream.[[reader]] gets nuked.

load(libdir + "asserts.js");

let g = newGlobal();
let stream = new ReadableStream({
    start(controller) {
        controller.enqueue("ponies");
        controller.close();
    }
});
g.stream = stream;
g.eval("var reader = ReadableStream.prototype.getReader.call(stream);");
nukeCCW(g.reader);
assertErrorMessage(() => g.eval("reader.read()"), g.TypeError, "can't access dead object");
g.eval("reader.releaseLock();");

vs

load(libdir + "asserts.js");

let g = newGlobal();

let stream = new ReadableStream(({
    start: (function(controller) {
        controller.enqueue("ponies");
        controller.close();
    }),
}));

g.stream = stream;

g.eval("var reader = ReadableStream.prototype.getReader.call(stream);");

nukeCCW(g.reader);

assertErrorMessage(()  => g.eval("reader.read()"), g.TypeError, "can't access dead object");

g.eval("reader.releaseLock();");
// |jit-test| --code-coverage;

// Currently the Jit integration has a few issues, let's keep this test
// case deterministic.
//
//  - Baseline OSR increments the loop header twice.
//  - Ion is not updating any counter yet.
//
if (getJitCompilerOptions()["ion.warmup.trigger"] != 30)
  setJitCompilerOption("ion.warmup.trigger", 30);
if (getJitCompilerOptions()["baseline.warmup.trigger"] != 10)
  setJitCompilerOption("baseline.warmup.trigger", 10);

/*
 * These test cases are annotated with the output produced by LCOV [1].  Comment
 * starting with //<key> without any spaces are used as a reference for the code
 * coverage output.  Any "$" in these line comments are replaced by the current
 * line number, and any "%" are replaced with the current function name (defined
 * by the FN key).
 *
 * [1]  http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php
 */
function checkLcov(fun) {
  var keys = [ "TN", "SF", "FN", "FNDA", "FNF", "FNH", "BRDA", "BRF", "BRH", "DA", "LF", "LH" ];
  function startsWithKey(s) {
    for (k of keys) {
      if (s.startsWith(k))
        return true;
    }
    return false;
  };

  // Extract the body of the function, as the code to be executed.
  var source = fun.toSource();
  source = source.slice(source.indexOf('{') + 1, source.lastIndexOf('}'));

  // Extract comment starting with the previous keys, as a reference of the
  // output expected from getLcovInfo.
  var lcovRef = [];
  var currLine = 0;
  var currFun = "<badfunction>";
  for (var line of source.split('\n')) {
    currLine++;
    for (var comment of line.split("//").slice(1)) {
      if (!startsWithKey(comment))
        continue;
      comment = comment.trim();
      if (comment.startsWith("FN:"))
        currFun = comment.split(',')[1];
      comment = comment.replace('$', currLine);
      comment = comment.replace('%', currFun);
      lcovRef.push(comment);
    }
  }

  // Evaluate the code, and generate the Lcov result from the execution. We have
  // to disable lazy parsing, as we rely on the ZoneCellIter to emulate the
  // behaviour of the finalizer.
  var g = newGlobal({ disableLazyParsing: true });
  g.eval(source);
  var lcovResRaw = getLcovInfo(g);

  // Check that all the lines are present the result.
  var lcovRes = lcovResRaw.split('\n');
  for (ref of lcovRef) {
    if (lcovRes.indexOf(ref) == -1) {
      print("Cannot find `" + ref + "` in the following Lcov result:\n", lcovResRaw);
      print("In the following source:\n", source);
      assertEq(true, false);
    }
  }
}

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  ",".split(','); //DA:$,1
  //FNF:1
  //FNH:1
  //LF:1
  //LH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  function f() {    //FN:$,f
    ",".split(','); //DA:$,0
  }
  ",".split(',');   //DA:$,1
  //FNF:2
  //FNH:1
  //LF:2
  //LH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  function f() {    //FN:$,f //FNDA:1,%
    ",".split(','); //DA:$,1
  }
  f();              //DA:$,1
  //FNF:2
  //FNH:2
  //LF:2
  //LH:2
});

checkLcov(function () { ','.split(','); //FN:$,top-level //FNDA:1,% //DA:$,1
  //FNF:1
  //FNH:1
  //LF:1
  //LH:1
});

checkLcov(function () { function f() { ','.split(','); } //FN:$,top-level //FNDA:1,% //FN:$,f //FNDA:1,f //DA:$,1
  f(); //DA:$,1
  //FNF:2
  //FNH:2
  //LF:2
  //LH:2
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 3)      //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0
    l.push('');           //DA:$,0
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:4
  //LH:3
  //BRF:2
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 2)      //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1
    l.push('');           //DA:$,1
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:4
  //LH:4
  //BRF:2
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 3)      //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0
    l.push('');           //DA:$,0
  else
    l.pop();              //DA:$,1
  //FNF:1
  //FNH:1
  //LF:4
  //LH:3
  //BRF:2
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 2)      //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1
    l.push('');           //DA:$,1
  else
    l.pop();              //DA:$,0
  //FNF:1
  //FNH:1
  //LF:4
  //LH:3
  //BRF:2
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 2)      //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1
    l.push('');           //DA:$,1
  else {
    if (l.length == 1)    //DA:$,0 //BRDA:$,1,0,- //BRDA:$,1,1,-
      l.pop();            //DA:$,0
  }
  //FNF:1
  //FNH:1
  //LF:5
  //LH:3
  //BRF:4
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  function f(i) { //FN:$,f //FNDA:2,%
    var x = 0;    //DA:$,2
    while (i--) { // Currently OSR wrongly count the loop header twice.
                  // So instead of DA:$,12 , we have DA:$,13 .
      x += i;     //DA:$,10
      x = x / 2;  //DA:$,10
    }
    return x;     //DA:$,2
    //BRF:2
    //BRH:2
  }

  f(5);           //DA:$,1
  f(5);           //DA:$,1
  //FNF:2
  //FNH:2
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  try {                     //DA:$,1
    var l = ",".split(','); //DA:$,1
    if (l.length == 2) {    //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1
      l.push('');           //DA:$,1
      throw l;              //DA:$,1
    }
    l.pop();                //DA:$,0
  } catch (x) {             //DA:$,1
    x.pop();                //DA:$,1
  }
  //FNF:1
  //FNH:1
  //LF:8
  //LH:7
  //BRF:2
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(',');   //DA:$,1
  try {                     //DA:$,1
    try {                   //DA:$,1
      if (l.length == 2) {  //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1
        l.push('');         //DA:$,1
        throw l;            //DA:$,1
      }
      l.pop();              //DA:$,0
    } finally {             //DA:$,1
      l.pop();              //DA:$,1
    }
  } catch (x) {             //DA:$,1
  }
  //FNF:1
  //FNH:1
  //LF:10
  //LH:9
  //BRF:2
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  function f() {            //FN:$,f //FNDA:1,%
    throw 1;                //DA:$,1
    f();                    //DA:$,0
  }
  var l = ",".split(',');   //DA:$,1
  try {                     //DA:$,1
    f();                    //DA:$,1
    f();                    //DA:$,0
  } catch (x) {             //DA:$,1
  }
  //FNF:2
  //FNH:2
  //LF:7
  //LH:5
  //BRF:0
  //BRH:0
});

// Test TableSwitch opcode
checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0
    case 0:
      l.push('0');        //DA:$,0
      break;
    case 1:
      l.push('1');        //DA:$,0
      break;
    case 2:
      l.push('2');        //DA:$,1
      break;
    case 3:
      l.push('3');        //DA:$,0
      break;
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:4
  //BRF:5
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:5
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
                          // Branches are ordered, and starting at 0
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 //BRDA:$,0,2,0 //BRDA:$,0,3,0 //BRDA:$,0,4,0
    case 5:
      l.push('5');        //DA:$,0
    case 4:
      l.push('4');        //DA:$,0
    case 3:
      l.push('3');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:4
  //BRF:5
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0 //BRDA:$,0,2,0
    case 2:
      l.push('2');        //DA:$,1
    case 5:
      l.push('5');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:5
  //LH:5
  //BRF:3
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 //BRDA:$,0,2,0
    case 3:
      l.push('1');        //DA:$,0
    case 5:
      l.push('5');        //DA:$,0
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:5
  //LH:3
  //BRF:3
  //BRH:1
});

// Unfortunately the differences between switch implementations leaks in the
// code coverage reports.
checkLcov(function () { //FN:$,top-level //FNDA:1,%
  function f(a) {         //FN:$,f //FNDA:2,%
    return a;             //DA:$,2
  }
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case f(-42):          //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1
      l.push('1');        //DA:$,0
    case f(51):           //DA:$,1 //BRDA:$,1,0,0 //BRDA:$,1,1,1
      l.push('5');        //DA:$,0
  }
  l.pop();                //DA:$,1
  //FNF:2
  //FNH:2
  //LF:8
  //LH:6
  //BRF:4
  //BRH:2
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 //BRDA:$,0,2,0 //BRDA:$,0,3,0
    case 0:
    case 1:
      l.push('0');        //DA:$,0
      l.push('1');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    case 2:
    case 3:
      l.push('2');        //DA:$,1
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
    default:
      l.push('1');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    default:
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    default:
      l.push('default');  //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:8
  //LH:5
  //BRF:5
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    default:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkLcov(function () { //FN:$,top-level //FNDA:1,%
  var l = ','.split(','); //DA:$,1
  if (l.length === 45) {  //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0
    switch (l[0]) {       //DA:$,0 //BRDA:$,1,0,- //BRDA:$,1,1,-
      case ',':
        l.push('0');      //DA:$,0
      default:
        l.push('1');      //DA:$,0
    }
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:6
  //LH:3
  //BRF:4
  //BRH:1
});

// These tests are not included in ../debug/Script-getOffsetsCoverage-01.js
// because we're specifically testing a feature of Lcov output that
// Debugger.Script doesn't have (the aggregation of hits that are on the
// same line but in different functions).
{
    checkLcov(function () { //FN:$,top-level //FNDA:1,%
        function f() { return 0; } var l = f(); //DA:$,2
        //FNF:2
        //FNH:2
        //LF:1
        //LH:1
    });

    // A single line has two functions on it, and both hit.
    checkLcov(function () { //FN:$,top-level //FNDA:1,%
        function f() { return 0; } function g() { return 1; } //DA:$,2
        var v = f() + g(); //DA:$,1
        //FNF:3
        //FNH:3
        //LF:2
        //LH:2
    });

    // A line has both function code and toplevel code, and only one of them hits.
    checkLcov(function () { //FN:$,top-level //FNDA:1,%
        if (1 === 2)  //DA:$,1
            throw "0 hits here"; function f() { return "1 hit here"; } //DA:$,1
        f();  //DA:$,1
        //FNF:2
        //FNH:2
        //LF:3
        //LH:3
    });
}

// If you add a test case here, do the same in
// jit-test/tests/debug/Script-getOffsetsCoverage-01.js

vs

if (getJitCompilerOptions()["ion.warmup.trigger"] != 30) setJitCompilerOption("ion.warmup.trigger", 30);


if (getJitCompilerOptions()["baseline.warmup.trigger"] != 10) setJitCompilerOption("baseline.warmup.trigger", 10);


function checkLcov(fun) {
    var keys = ["TN", "SF", "FN", "FNDA", "FNF", "FNH", "BRDA", "BRF", "BRH", "DA", "LF", "LH",];
    function startsWithKey(s) {
        for (k of keys) {
            if (s.startsWith(k)) return true;

        }
        return false;
    }
    ;
    var source = fun.toSource();
    source = source.slice(source.indexOf('{') + 1, source.lastIndexOf('}'));
    var lcovRef = [];
    var currLine = 0;
    var currFun = "<badfunction>";
    for (line of source.split('\n')) {
        currLine++;

        for (comment of line.split("//").slice(1)) {
            if (!startsWithKey(comment)) continue;


            comment = comment.trim();

            if (comment.startsWith("FN:")) currFun = comment.split(',')[1];


            comment = comment.replace('$', currLine);

            comment = comment.replace('%', currFun);

            lcovRef.push(comment);
        }
    }
    var g = newGlobal({
        disableLazyParsing: true,
    });
    g.eval(source);
    var lcovResRaw = getLcovInfo(g);
    var lcovRes = lcovResRaw.split('\n');
    for (ref of lcovRef) {
        if (lcovRes.indexOf(ref) == -1) {
            print("Cannot find `" + ref + "` in the following Lcov result:\n", lcovResRaw);

            print("In the following source:\n", source);

            assertEq(true, false);
        }
    }
}

checkLcov((function() {
    ",".split(',');
}));

checkLcov((function() {
    function f() {
        ",".split(',');
    }
    ",".split(',');
}));

checkLcov((function() {
    function f() {
        ",".split(',');
    }
    f();
}));

checkLcov((function() {
    ','.split(',');
}));

checkLcov((function() {
    function f() {
        ','.split(',');
    }
    f();
}));

checkLcov((function() {
    var l = ",".split(',');
    if (l.length == 3) l.push('');

    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    if (l.length == 2) l.push('');

    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    if (l.length == 3) l.push('');
 else l.pop();

}));

checkLcov((function() {
    var l = ",".split(',');
    if (l.length == 2) l.push('');
 else l.pop();

}));

checkLcov((function() {
    var l = ",".split(',');
    if (l.length == 2) l.push('');
 else {
        if (l.length == 1) l.pop();

    }
}));

checkLcov((function() {
    function f(i) {
        var x = 0;
        while (i--) {
            x += i;

            x = x / 2;
        }
        return x;
    }
    f(5);
    f(5);
}));

checkLcov((function() {
    try {
        var l = ",".split(',');

        if (l.length == 2) {
            l.push('');

            throw l;
        }

        l.pop();
    } catch (x) {
        x.pop();
    }
}));

checkLcov((function() {
    var l = ",".split(',');
    try {
        try {
            if (l.length == 2) {
                l.push('');

                throw l;
            }

            l.pop();
        } finally {
            l.pop();
        }
    } catch (x) { 
        
    }
}));

checkLcov((function() {
    function f() {
        throw 1;
        f();
    }
    var l = ",".split(',');
    try {
        f();

        f();
    } catch (x) { 
        
    }
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        break;

        case 1:
            l.push('1');

        break;

        case 2:
            l.push('2');

        break;

        case 3:
            l.push('3');

        break;

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 5:
            l.push('5');

        case 4:
            l.push('4');

        case 3:
            l.push('3');

        case 2:
            l.push('2');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 2:
            l.push('2');

        case 5:
            l.push('5');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 3:
            l.push('1');

        case 5:
            l.push('5');

    }
    l.pop();
}));

checkLcov((function() {
    function f(a) {
        return a;
    }
    var l = ",".split(',');
    switch (l.length) {
        case f(-42):
            l.push('1');

        case f(51):
            l.push('5');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
        case 1:
            l.push('0');

            l.push('1');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        case 2:
        case 3:
            l.push('2');

            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
        default:
            l.push('1');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        default:
        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        default:
            l.push('default');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        default:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkLcov((function() {
    var l = ','.split(',');
    if (l.length === 45) {
        switch (l[0]) {
            case ',':
                l.push('0');

            default:
                l.push('1');

        }
    }
    l.pop();
}));

{
    checkLcov(function() {
        function f() {
            return 0;
        }
        var l = f();
    });

    checkLcov(function() {
        function f() {
            return 0;
        }
        function g() {
            return 1;
        }
        var v = f() + g();
    });

    checkLcov(function() {
        if (1 === 2) throw "0 hits here";

        function f() {
            return "1 hit here";
        }
        f();
    });
}
// for-of works on arrays.

var a = ['a', 'b', 'c'];
var s = '';
for (var v of a)
    s += v;
assertEq(s, 'abc');

vs

var a = ['a', 'b', 'c',];

var s = '';

for (v of a) s += v;

assertEq(s, 'abc');
// for-of can iterate strict arguments objects in non-strict code.

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;
function g(obj) {
    for (var v of obj)
        s += v;
}

function f() {
    "use strict";
    g(arguments);
}

s = '';
f(1, 2, 3);
assertEq(s, '123');

vs

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;

function g(obj) {
    for (v of obj) s += v;
}

function f() {
    'use strict';
    g(arguments);
}

s = '';

f(1, 2, 3);

assertEq(s, '123');
// Test that each yield* loop just checks "done", and "value" is only
// fetched once at the end.

load(libdir + 'iteration.js');

var log = "";

function Iter(val, count) {
    function next() {
        return {
            get done() { log += "d"; return count-- == 0; },
            get value() { log += "v"; return val; }
        }
    }

    this[Symbol.iterator] = function() { return this; };
    this.next = next;
}

for (var x of new Iter(42, 5))
    assertEq(x, 42);

assertEq(log, "dvdvdvdvdvd");

vs

load(libdir + 'iteration.js');

var log = "";

function Iter(val, count) {
    function next() {
        return {
            get done() {
                log += "d";
                return count-- == 0;
            },
            get value() {
                log += "v";
                return val;
            },
        };
    }
    this[Symbol.iterator] = function() {
        return this;
    };
    this.next = next;
}

for (x of new Iter(42, 5)) assertEq(x, 42);

assertEq(log, "dvdvdvdvdvd");
// A labeled break statement can leave multiple for-loops

var log = '';
for (var i = 0; i < 3; i++) {
    a: for (var x of [1, 2, 3]) {
        for (var y of ['.', ':']) {
            log += x + y;
            break a;
        }
    }
}
assertEq(log, "1.1.1.");

vs

var log = '';

for (let i = 0;i < 3;i++) {
    a: for (x of [1, 2, 3,]) {
        for (y of ['.', ':',]) {
            log += x + y;

            break a;
        }
    }

}

assertEq(log, "1.1.1.");
// for-of works on cross-compartment wrappers of Arrays.

var g = newGlobal();
var s = '';
for (var x of g.Array(1, 1, 2, 3, 5))
    s += x;
assertEq(s, '11235');

vs

var g = newGlobal();

var s = '';

for (x of g.Array(1, 1, 2, 3, 5)) s += x;

assertEq(s, '11235');
var arr = [1, 2, 3];
var y = 0;
for (var i = 0; i < 10; i++)
    for (var x of arr)
        y += x;
assertEq(y, 60);

vs

var arr = [1, 2, 3,];

var y = 0;

for (let i = 0;i < 10;i++) for (x of arr) y += x;

assertEq(y, 60);
// for-of can iterate arguments objects.

load(libdir + "iteration.js");

// Arguments objects do not have a .@@iterator() method by default.
// Install one on Object.prototype.
Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;
function test() {
    for (var v of arguments)
        s += v;
}

s = '';
test();
assertEq(s, '');

s = '';
test('x', 'y');
assertEq(s, 'xy');

vs

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;

function test() {
    for (v of arguments) s += v;
}

s = '';

test();

assertEq(s, '');

s = '';

test('x', 'y');

assertEq(s, 'xy');
// Rest parameters are allowed in arrow functions.

var A = (...x) => x;
assertEq(A().toSource(), "[]");
assertEq("" + A(3, 4, 5), "3,4,5");

vs

var A = x => x;

assertEq(A().toSource(), "[]");

assertEq("" + A(3, 4, 5), "3,4,5");
/**
 * A test case spec is an array of objects of the following kind:
 *  { 'match': Num|Str|Null,
 *    'body': Num|Str|Null,
 *    'fallthrough': Boolean }
 *
 * If the 'match' is null, then it represents a 'default:'
 * If the 'match' is not null, it represents a 'case X:' where X is the value.
 * If the 'body' is null, then it means that the case body is empty.  Otherwise,
 * it means that the case body is a single 'arr.push(V);' where "arr" is an input
 * array to the function containing the switch statement, and V is the value.
 * If 'fallthrough' is false, then the body is terminated with a break, otherwise
 * it is not.
 *
 * So a spec: [{'match':3, 'body':null, 'fallthrough':false}, {'match':null, 'body':"foo", 'fallthrough':true}]
 * Represents a switch function:
 *  function(x, arr) {
 *      switch(x) {
 *      case 3:
 *          break;
 *      default:
 *          arr.push('foo');
 *      }
 *  }
 *
 * GenerateSpecPermutes generates a bunch of relevant specs, using the given case match-values,
 * and appends them to result the array passed into it.
 *
 * InterpretSwitch takes a spec, a value, and a result array, and behaves as if the switch specified
 * by the spec had been called on the value and the result array.
 *
 * VerifySwitchSpec is there but not used in the code.  I was using it while testing the test case
 * generator.  It verifies that a switch spec is sane.
 *
 * RunSpec uses eval to run the test directly.  It's not used currently.
 *
 * GenerateSwitchCode generates a string of the form "function NAME(x, arg) { .... }" which
 * contains the switch modeled by its input spec.
 *
 * RunTest is there to be used from within the generated script.  Its code is dumped out
 * to the generated script text, and invoked there.
 *
 * Hope all of this makes some sort of sense.
 *  -kannan
 */

/** HELPERS **/

function ASSERT(cond, msg) { assertEq(cond, true, msg); }

function IsUndef(x) { return typeof(x) == 'undefined'; }
function IsNull(x) { return typeof(x) == 'object' && x == null; }
function IsNum(x) { return typeof(x) == 'number'; }
function IsStr(x) { return typeof(x) == 'string'; }
function IsBool(x) { return typeof(x) == 'boolean'; }

function Repr(x) {
    ASSERT(IsNum(x) || IsStr(x), "Repr");
    if(IsNum(x)) { return ""+x; }
    else { return "'"+x+"'"; }
}

function RandBool() { return Math.random() >= 0.5; }
function RandInt(max) {
    if(IsUndef(max)) { max = 0x7fffffff; }
    return (Math.random() * max)|0;
}

var CHARS = "abcdefghijklmnopqrstuvywxyzABCDEFGHIJKLMNOPQRSTUVYWXYZ0123456789~!@#$%^&*()-_=+{}[]";
function RandStr() {
    var arr = [];
    var len = Math.floor(Math.random() * 10) + 1;
    for(var i = 0; i < len; i++) {
        var c = Math.floor(Math.random() * CHARS.length);
        arr.push(CHARS[c]);
    }
    return arr.join('');
}

function RandVal() { return RandBool() ? RandInt() : RandStr(); }

/**
 * Compare two arrays and ensure they are equal.
 */
function ArraysEqual(arr1, arr2) {
    ASSERT(arr1.length == arr2.length, "Lengths not equal");
    for(var i = 0; i < arr1.length; i++) {
        ASSERT(typeof(arr1[i]) == typeof(arr2[i]), "Types not equal for position " + i);
        ASSERT(arr1[i] == arr2[i], "Values not equal for position " + i);
    }
}

function VerifySwitchSpec(spec) {
    var foundDefault = undefined;
    for(var i = 0; i < spec.length; i++) {
        var caseSpec = spec[i],
            match = caseSpec.match,
            body = caseSpec.body,
            fallthrough = caseSpec.fallthrough;
        ASSERT(IsNum(match) || IsStr(match) || IsNull(match), "Invalid case match for " + i);
        ASSERT(IsNum(body) || IsStr(body) || IsNull(body), "Invalid case body for " + i);
        ASSERT(IsBool(fallthrough), "Invalid fallthrough for " + i);

        if(IsNull(match)) {
            ASSERT(IsUndef(foundDefault), "Duplicate default found at " + i);
            foundDefault = i;
        }
    }
}

/**
 * Do a manual interpretation of a particular spec, given an input
 * and outputting to an output array.
 */
function InterpretSwitch(spec, input, outputArray) {
    var foundMatch = undefined, foundDefault = undefined;
    // Go through cases, trying to find a matching clause.
    for(var i = 0; i < spec.length; i++) {
        var caseSpec = spec[i], match = caseSpec.match;

        if(IsNull(match)) {
            foundDefault = i;
            continue;
        } else if(match === input) {
            foundMatch = i;
            break;
        }
    }
    // Select either matching clause or default.
    var matchI = IsNum(foundMatch) ? foundMatch : foundDefault;

    // If match or default was found, interpret body from that point on.
    if(IsNum(matchI)) {
        for(var i = matchI; i < spec.length; i++) {
            var caseSpec = spec[i],
                match = caseSpec.match,
                body = caseSpec.body,
                fallthrough = caseSpec.fallthrough;
            if(!IsNull(body)) { outputArray.push(body); }
            if(!fallthrough) { break; }
        }
    }
}

/**
 * Generate the code string for a javascript function containing the
 * switch specified by the spec, in pure JS syntax.
 */
function GenerateSwitchCode(spec, name) {
    var lines = [];
    if(!name) { name = ""; }

    lines.push("function "+name+"(x, arr) {");
    lines.push("    switch(x) {");
    for(var i = 0; i < spec.length; i++) {
        var caseSpec = spec[i],
            match = caseSpec.match,
            body = caseSpec.body,
            fallthrough = caseSpec.fallthrough;

        if(IsNull(match))   { lines.push("    default:"); }
        else                { lines.push("    case "+Repr(match)+":"); }

        if(!IsNull(body))   { lines.push("        arr.push("+Repr(body)+");"); }
        if(!fallthrough)    { lines.push("        break;"); }
    }
    lines.push("    }");
    lines.push("}");
    return lines.join("\n");
}

/**
 * Generates all possible specs for a given set of case match values.
 */
function GenerateSpecPermutes(matchVals, resultArray) {
    ASSERT((0 < matchVals.length) && (matchVals.length <= 5), "Invalid matchVals");
    var maxPermuteBody = (1 << matchVals.length) - 1;
    for(var bod_pm = 0; bod_pm <= maxPermuteBody; bod_pm++) {
        var maxPermuteFallthrough = (1 << matchVals.length) - 1;

        for(var ft_pm = 0; ft_pm <= maxPermuteFallthrough; ft_pm++) {
            // use bod_m and ft_pm to decide the placement of null vs value bodies,
            // and the placement of fallthroughs vs breaks.
            // Empty bodies always fall through, so fallthrough bitmask 1s must be
            // a subset of the body bitmask 1s.
            if((bod_pm | ft_pm) != bod_pm) {
                continue;
            }

            var spec = [];
            for(var k = 0; k < matchVals.length; k++) {
                var match = matchVals[k];
                var body = ((bod_pm & (1 << k)) > 0) ? null : RandVal();
                var fallthrough = ((ft_pm & (1 << k)) > 0) ? true : false;
                var caseSpec = {'match':match, 'body':body, 'fallthrough':fallthrough};
                spec.push(caseSpec);
            }

            // Variant specs for following cases:

            // Default with empty body, fallthrough
            GenerateDefaultPermutes(spec, null, true, resultArray);
            // Default with nonempty body, fallthrough
            GenerateDefaultPermutes(spec, RandVal(), true, resultArray);
            // Default with nonempty body, break
            GenerateDefaultPermutes(spec, RandVal(), false, resultArray);
        }
    }
}
function GenerateDefaultPermutes(spec, body, fallthrough, resultArray) {
    if(spec.length <= 2) {
        for(var i = 0; i <= spec.length; i++) {
            var copy = CopySpec(spec);
            if(IsNull(body)) {
                copy.splice(i,0,{'match':null, 'body':null, 'fallthrough':true});
            } else {
                copy.splice(i,0,{'match':null, 'body':body, 'fallthrough':fallthrough});
            }
            resultArray.push(copy);
        }
    } else {
        var posns = [0, Math.floor(spec.length / 2), spec.length];
        posns.forEach(function (i) {
            var copy = CopySpec(spec);
            if(IsNull(body)) {
                copy.splice(i,0,{'match':null, 'body':null, 'fallthrough':true});
            } else {
                copy.splice(i,0,{'match':null, 'body':body, 'fallthrough':fallthrough});
            }
            resultArray.push(copy);
        });
    }
}
function CopySpec(spec) {
    var newSpec = [];
    for(var i = 0; i < spec.length; i++) {
        var caseSpec = spec[i];
        newSpec.push({'match':caseSpec.match,
                      'body':caseSpec.body,
                      'fallthrough':caseSpec.fallthrough});
    }
    return newSpec;
}


function RunSpec(spec, matchVals) {
    var code = GenerateSwitchCode(spec);

    // Generate roughly 200 inputs for the test case spec, exercising
    // every match value, as well as 3 randomly generated values for every
    // iteration of the match values.
    var inputs = [];
    while(inputs.length < 500) {
        for(var i = 0; i < matchVals.length; i++) { inputs.push(matchVals[i]); }
        for(var i = 0; i < 3; i++) { inputs.push(RandVal()); }
    }

    // Interpret the lookupswitch with the inputs.
    var interpResults = [];
    for(var i = 0; i < inputs.length; i++) {
        InterpretSwitch(spec, inputs[i], interpResults);
    }

    // Run compiled lookupswitch with the inputs.
    var fn = eval("_ = " + code);
    print("Running spec: " + code);
    var compileResults = RunCompiled(fn, inputs);
    print("Done Running spec");

    // Verify that they produce the same output.
    ASSERT(interpResults.length == compileResults.length, "Length mismatch");
    for(var i = 0; i < interpResults.length; i++) {
        ASSERT(interpResults[i] == compileResults[i], "Value mismatch");
    }
}
function RunCompiled(fn, inputs) {
    var results = [];
    var len = inputs.length;
    for(var i = 0; i < len; i++) { fn(inputs[i], results); }
    return results;
}

function PrintSpec(spec, inputs, fname) {
    var code = GenerateSwitchCode(spec, fname);
    var input_s = fname + ".INPUTS = [" + inputs.map(Repr).join(', ') + "];";
    var spec_s = fname + ".SPEC = " + JSON.stringify(spec) + ";";
    print(code + "\n" + input_s + "\n" + spec_s);
}

function RunTest(test) {
    // Exercise every test case as well as one case which won't match with any of the
    // ("But what if it randomly generates a string case match whose value is
    //   UNMATCHED_CASE?!", you ask incredulously.  Well, RandStr limits itself to 11 chars.
    //   So there.)
    var inputs = test.INPUTS;
    inputs.push("UNMATCHED_CASE");
    var spec = test.SPEC;

    var results1 = [];
    for(var i = 0; i < 80; i++) {
        for(var j = 0; j < inputs.length; j++) {
            test(inputs[j], results1);
        }
    }

    var results2 = [];
    for(var i = 0; i < 80; i++) {
        for(var j = 0; j < inputs.length; j++) {
            InterpretSwitch(spec, inputs[j], results2);
        }
    }
    ArraysEqual(results1, results2);
}

// NOTES:
//  * RunTest is used within the generated test script.
//  * InterpretSwitch is printed out into the generated test script.

print("/////////////////////////////////////////");
print("// This is a generated file!");
print("// See jit-tests/etc/generate-lookupswitch-tests.js for the code");
print("// that generated this code!");
print("/////////////////////////////////////////");
print("");
print("/////////////////////////////////////////");
print("// PRELUDE                             //");
print("/////////////////////////////////////////");
print("");
print("// Avoid eager compilation of the global-scope.");
print("try{} catch (x) {};");
print("");
print(ASSERT);
print(IsNull);
print(IsNum);
print(ArraysEqual);
print(InterpretSwitch);
print(RunTest);
print("");
print("/////////////////////////////////////////");
print("// TEST CASES                          //");
print("/////////////////////////////////////////");
print("");
print("var TESTS = [];");
var MATCH_SETS = [["foo", "bar", "zing"]];
var count = 0;
for(var i = 0; i < MATCH_SETS.length; i++) {
    var matchSet = MATCH_SETS[i];
    var specs = [];
    GenerateSpecPermutes(matchSet, specs);
    for(var j = 0; j < specs.length; j++) {
        count++;
        PrintSpec(specs[j], matchSet.slice(), 'test_'+count);
        print("TESTS.push(test_"+count+");\n");
    }
}

print("");
print("/////////////////////////////////////////");
print("// RUNNER                              //");
print("/////////////////////////////////////////");
print("");
print("for(var i = 0; i < TESTS.length; i++) {");
print("  RunTest(TESTS[i]);");
print("}");

vs

function ASSERT(cond, msg) {
    assertEq(cond, true, msg);
}

function IsUndef(x) {
    return typeof x == 'undefined';
}

function IsNull(x) {
    return typeof x == 'object' && x == null;
}

function IsNum(x) {
    return typeof x == 'number';
}

function IsStr(x) {
    return typeof x == 'string';
}

function IsBool(x) {
    return typeof x == 'boolean';
}

function Repr(x) {
    ASSERT(IsNum(x) || IsStr(x), "Repr");
    if (IsNum(x)) {
        return "" + x;
    } else {
        return "'" + x + "'";
    }
}

function RandBool() {
    return Math.random() >= 0.5;
}

function RandInt(max) {
    if (IsUndef(max)) {
        max = 0x7fffffff;
    }
    return Math.random() * max | 0;
}

var CHARS = "abcdefghijklmnopqrstuvywxyzABCDEFGHIJKLMNOPQRSTUVYWXYZ0123456789~!@#$%^&*()-_=+{}[]";

function RandStr() {
    var arr = [];
    var len = Math.floor(Math.random() * 10) + 1;
    for (let i = 0;i < len;i++) {
        var c = Math.floor(Math.random() * CHARS.length);

        arr.push(CHARS[c]);
    }
    return arr.join('');
}

function RandVal() {
    return RandBool() ? RandInt() : RandStr();
}

function ArraysEqual(arr1, arr2) {
    ASSERT(arr1.length == arr2.length, "Lengths not equal");
    for (let i = 0;i < arr1.length;i++) {
        ASSERT(typeof arr1[i] == typeof arr2[i], "Types not equal for position " + i);

        ASSERT(arr1[i] == arr2[i], "Values not equal for position " + i);
    }
}

function VerifySwitchSpec(spec) {
    var foundDefault = undefined;
    for (let i = 0;i < spec.length;i++) {
        var caseSpec = spec[i], match = caseSpec.match, body = caseSpec.body, fallthrough = caseSpec.fallthrough;

        ASSERT(IsNum(match) || IsStr(match) || IsNull(match), "Invalid case match for " + i);

        ASSERT(IsNum(body) || IsStr(body) || IsNull(body), "Invalid case body for " + i);

        ASSERT(IsBool(fallthrough), "Invalid fallthrough for " + i);

        if (IsNull(match)) {
            ASSERT(IsUndef(foundDefault), "Duplicate default found at " + i);

            foundDefault = i;
        }
    }
}

function InterpretSwitch(spec, input, outputArray) {
    var foundMatch = undefined, foundDefault = undefined;
    for (let i = 0;i < spec.length;i++) {
        var caseSpec = spec[i], match = caseSpec.match;

        if (IsNull(match)) {
            foundDefault = i;

            continue;
        } else if (match === input) {
            foundMatch = i;

            break;
        }

    }
    var matchI = IsNum(foundMatch) ? foundMatch : foundDefault;
    if (IsNum(matchI)) {
        for (let i = matchI;i < spec.length;i++) {
            var caseSpec = spec[i], match = caseSpec.match, body = caseSpec.body, fallthrough = caseSpec.fallthrough;

            if (!IsNull(body)) {
                outputArray.push(body);
            }

            if (!fallthrough) {
                break;
            }
        }
    }
}

function GenerateSwitchCode(spec, name) {
    var lines = [];
    if (!name) {
        name = "";
    }
    lines.push("function " + name + "(x, arr) {");
    lines.push("    switch(x) {");
    for (let i = 0;i < spec.length;i++) {
        var caseSpec = spec[i], match = caseSpec.match, body = caseSpec.body, fallthrough = caseSpec.fallthrough;

        if (IsNull(match)) {
            lines.push("    default:");
        } else {
            lines.push("    case " + Repr(match) + ":");
        }

        if (!IsNull(body)) {
            lines.push("        arr.push(" + Repr(body) + ");");
        }

        if (!fallthrough) {
            lines.push("        break;");
        }
    }
    lines.push("    }");
    lines.push("}");
    return lines.join("\n");
}

function GenerateSpecPermutes(matchVals, resultArray) {
    ASSERT(0 < matchVals.length && matchVals.length <= 5, "Invalid matchVals");
    var maxPermuteBody = 1 << matchVals.length - 1;
    for (let bod_pm = 0;bod_pm <= maxPermuteBody;bod_pm++) {
        var maxPermuteFallthrough = 1 << matchVals.length - 1;

        for (let ft_pm = 0;ft_pm <= maxPermuteFallthrough;ft_pm++) {
            if (bod_pm | ft_pm != bod_pm) {
                continue;
            }

            var spec = [];

            for (let k = 0;k < matchVals.length;k++) {
                var match = matchVals[k];

                var body = bod_pm & 1 << k > 0 ? null : RandVal();

                var fallthrough = ft_pm & 1 << k > 0 ? true : false;

                var caseSpec = {
                    'match': match,
                    'body': body,
                    'fallthrough': fallthrough,
                };

                spec.push(caseSpec);
            }

            GenerateDefaultPermutes(spec, null, true, resultArray);

            GenerateDefaultPermutes(spec, RandVal(), true, resultArray);

            GenerateDefaultPermutes(spec, RandVal(), false, resultArray);
        }
    }
}

function GenerateDefaultPermutes(spec, body, fallthrough, resultArray) {
    if (spec.length <= 2) {
        for (let i = 0;i <= spec.length;i++) {
            var copy = CopySpec(spec);

            if (IsNull(body)) {
                copy.splice(i, 0, {
                    'match': null,
                    'body': null,
                    'fallthrough': true,
                });
            } else {
                copy.splice(i, 0, {
                    'match': null,
                    'body': body,
                    'fallthrough': fallthrough,
                });
            }

            resultArray.push(copy);
        }
    } else {
        var posns = [0, Math.floor(spec.length / 2), spec.length,];

        posns.forEach(function(i) {
            var copy = CopySpec(spec);
            if (IsNull(body)) {
                copy.splice(i, 0, {
                    'match': null,
                    'body': null,
                    'fallthrough': true,
                });
            } else {
                copy.splice(i, 0, {
                    'match': null,
                    'body': body,
                    'fallthrough': fallthrough,
                });
            }
            resultArray.push(copy);
        });
    }
}

function CopySpec(spec) {
    var newSpec = [];
    for (let i = 0;i < spec.length;i++) {
        var caseSpec = spec[i];

        newSpec.push({
            'match': caseSpec.match,
            'body': caseSpec.body,
            'fallthrough': caseSpec.fallthrough,
        });
    }
    return newSpec;
}

function RunSpec(spec, matchVals) {
    var code = GenerateSwitchCode(spec);
    var inputs = [];
    while (inputs.length < 500) {
        for (let i = 0;i < matchVals.length;i++) {
            inputs.push(matchVals[i]);
        }

        for (let i = 0;i < 3;i++) {
            inputs.push(RandVal());
        }
    }
    var interpResults = [];
    for (let i = 0;i < inputs.length;i++) {
        InterpretSwitch(spec, inputs[i], interpResults);
    }
    var fn = eval("_ = " + code);
    print("Running spec: " + code);
    var compileResults = RunCompiled(fn, inputs);
    print("Done Running spec");
    ASSERT(interpResults.length == compileResults.length, "Length mismatch");
    for (let i = 0;i < interpResults.length;i++) {
        ASSERT(interpResults[i] == compileResults[i], "Value mismatch");
    }
}

function RunCompiled(fn, inputs) {
    var results = [];
    var len = inputs.length;
    for (let i = 0;i < len;i++) {
        fn(inputs[i], results);
    }
    return results;
}

function PrintSpec(spec, inputs, fname) {
    var code = GenerateSwitchCode(spec, fname);
    var input_s = fname + ".INPUTS = [" + inputs.map(Repr).join(', ') + "];";
    var spec_s = fname + ".SPEC = " + JSON.stringify(spec) + ";";
    print(code + "\n" + input_s + "\n" + spec_s);
}

function RunTest(test) {
    var inputs = test.INPUTS;
    inputs.push("UNMATCHED_CASE");
    var spec = test.SPEC;
    var results1 = [];
    for (let i = 0;i < 80;i++) {
        for (let j = 0;j < inputs.length;j++) {
            test(inputs[j], results1);
        }
    }
    var results2 = [];
    for (let i = 0;i < 80;i++) {
        for (let j = 0;j < inputs.length;j++) {
            InterpretSwitch(spec, inputs[j], results2);
        }
    }
    ArraysEqual(results1, results2);
}

print("/////////////////////////////////////////");

print("// This is a generated file!");

print("// See jit-tests/etc/generate-lookupswitch-tests.js for the code");

print("// that generated this code!");

print("/////////////////////////////////////////");

print("");

print("/////////////////////////////////////////");

print("// PRELUDE                             //");

print("/////////////////////////////////////////");

print("");

print("// Avoid eager compilation of the global-scope.");

print("try{} catch (x) {};");

print("");

print(ASSERT);

print(IsNull);

print(IsNum);

print(ArraysEqual);

print(InterpretSwitch);

print(RunTest);

print("");

print("/////////////////////////////////////////");

print("// TEST CASES                          //");

print("/////////////////////////////////////////");

print("");

print("var TESTS = [];");

var MATCH_SETS = [["foo", "bar", "zing",],];

var count = 0;

for (let i = 0;i < MATCH_SETS.length;i++) {
    var matchSet = MATCH_SETS[i];

    var specs = [];

    GenerateSpecPermutes(matchSet, specs);

    for (let j = 0;j < specs.length;j++) {
        count++;

        PrintSpec(specs[j], matchSet.slice(), 'test_' + count);

        print("TESTS.push(test_" + count + ");\n");
    }
}

print("");

print("/////////////////////////////////////////");

print("// RUNNER                              //");

print("/////////////////////////////////////////");

print("");

print("for(var i = 0; i < TESTS.length; i++) {");

print("  RunTest(TESTS[i]);");

print("}");
// for-of throws if the target is a typed array prototype object.

load(libdir + "asserts.js");
assertThrowsInstanceOf(function () {
    for (var v of Int8Array.prototype)
        throw "FAIL";
}, TypeError);

vs

load(libdir + "asserts.js");

assertThrowsInstanceOf((function() {
    for (v of Int8Array.prototype) throw "FAIL";
}), TypeError);
class C { };
C.prototype.a = "a";
C.prototype.b = "b";
C.prototype.c = "c";
C.prototype.d = "d";
C.prototype.e = "e";
C.prototype.f = "f";
C.prototype.g = "g";
C.prototype.h = "h";
C.prototype.i = "i";
C.prototype.j = "j";
C.prototype.k = "k";
C.prototype.l = "l";
C.prototype.m = "m";
C.prototype.n = "n";
C.prototype.o = "o";
C.prototype.p = "p";
C.prototype.q = "q";
C.prototype.r = "r";

class D extends C {
    foo(p) {
        return super[p];
    }
}

var d = new D();

for (let i = 0; i < 20; ++i) {
    for (let p in C.prototype) {
        assertEq(p, d.foo(p));
    }
}

vs

class C {
}

;

C.prototype.a = "a";

C.prototype.b = "b";

C.prototype.c = "c";

C.prototype.d = "d";

C.prototype.e = "e";

C.prototype.f = "f";

C.prototype.g = "g";

C.prototype.h = "h";

C.prototype.i = "i";

C.prototype.j = "j";

C.prototype.k = "k";

C.prototype.l = "l";

C.prototype.m = "m";

C.prototype.n = "n";

C.prototype.o = "o";

C.prototype.p = "p";

C.prototype.q = "q";

C.prototype.r = "r";

class D extends C {

    foo(p) {
        return super[p];
    }
}

var d = new D();

for (let i = 0;i < 20;++i) {
    for (p in C.prototype) {
        assertEq(p, d.foo(p));
    }
}
// Nested for-of loops on the same slow array get distinct iterators.

var a = [1, 2, 3];
a.slow = true;
var s = '';
for (var x of a)
    for (var y of a)
        s += '' + x + y + ',';
assertEq(s, '11,12,13,21,22,23,31,32,33,');

vs

var a = [1, 2, 3,];

a.slow = true;

var s = '';

for (x of a) for (y of a) s += '' + x + y + ',';

assertEq(s, '11,12,13,21,22,23,31,32,33,');
// Superficial tests for iterators created by Array.prototype.iterator

load(libdir + "iteration.js");

var proto = Object.getPrototypeOf([][Symbol.iterator]());
var iterProto = Object.getPrototypeOf(proto);
proto = Object.getPrototypeOf([].keys());
assertEq(Object.getPrototypeOf(proto), iterProto);
proto = Object.getPrototypeOf([].entries());
assertEq(Object.getPrototypeOf(proto), iterProto);

function check(it) {
    assertEq(typeof it, 'object');
    assertEq(Object.getPrototypeOf(it), proto);
    assertEq(Object.getOwnPropertyNames(it).length, 0);
    assertEq(it[Symbol.iterator](), it);

    // for-in enumerates the iterator's properties.
    it.x = 0;
    var s = '';
    for (var p in it)
        s += p + '.';
    assertEq(s, 'x.');
}

check([][Symbol.iterator]());
check(Array.prototype[Symbol.iterator].call({}));
check([].keys());
check(Array.prototype.keys.call({}));
check([].entries());
check(Array.prototype.entries.call({}));

vs

load(libdir + "iteration.js");

var proto = Object.getPrototypeOf([][Symbol.iterator]());

var iterProto = Object.getPrototypeOf(proto);

proto = Object.getPrototypeOf([].keys());

assertEq(Object.getPrototypeOf(proto), iterProto);

proto = Object.getPrototypeOf([].entries());

assertEq(Object.getPrototypeOf(proto), iterProto);

function check(it) {
    assertEq(typeof it, 'object');
    assertEq(Object.getPrototypeOf(it), proto);
    assertEq(Object.getOwnPropertyNames(it).length, 0);
    assertEq(it[Symbol.iterator](), it);
    it.x = 0;
    var s = '';
    for (p in it) s += p + '.';
    assertEq(s, 'x.');
}

check([][Symbol.iterator]());

check(Array.prototype[Symbol.iterator].call(({})));

check([].keys());

check(Array.prototype.keys.call(({})));

check([].entries());

check(Array.prototype.entries.call(({})));
load(libdir + "asserts.js");

// 'arguments' is allowed in a non-arrow-function with a rest param.
assertEq((function(...rest) { return (x => arguments)(1, 2)})().length, 0);

function restAndArgs(...rest) {
    return () => eval("arguments");
}

var args = restAndArgs(1, 2, 3)();
assertEq(args.length, 3);
assertEq(args[0], 1);
assertEq(args[1], 2);
assertEq(args[2], 3);

(function() {
    return ((...rest) => {
        assertDeepEq(rest, [1, 2, 3]);
        assertEq(arguments.length, 2);
        assertEq(eval("arguments").length, 2);
    })(1, 2, 3);
})(4, 5);

vs

load(libdir + "asserts.js");

assertEq((function(rest) {
    return x => arguments(1, 2);
})().length, 0);

function restAndArgs(rest) {
    return ()  => eval("arguments");
}

var args = restAndArgs(1, 2, 3)();

assertEq(args.length, 3);

assertEq(args[0], 1);

assertEq(args[1], 2);

assertEq(args[2], 3);

(function() {
    return rest => {
        assertDeepEq(rest, [1, 2, 3,]);
        assertEq(arguments.length, 2);
        assertEq(eval("arguments").length, 2);
    }(1, 2, 3);
})(4, 5);
// Deleting String.prototype.iterator makes for-of stop working on strings.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

delete String.prototype[Symbol.iterator];
assertThrowsInstanceOf(function () { for (var v of "abc") ; }, TypeError);
assertThrowsInstanceOf(function () { for (var v of new String("abc")) ; }, TypeError);

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

delete String.prototype[Symbol.iterator];

assertThrowsInstanceOf((function() {
    for (v of "abc") ;
}), TypeError);

assertThrowsInstanceOf((function() {
    for (v of new String("abc")) ;
}), TypeError);
// for-of can iterate arguments objects after returning.

load(libdir + "iteration.js");

function f() {
    return arguments;
}

var s = '';
var args = f('a', 'b', 'c');
Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
for (var v of args)
    s += v;
assertEq(s, 'abc');

vs

load(libdir + "iteration.js");

function f() {
    return arguments;
}

var s = '';

var args = f('a', 'b', 'c');

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

for (v of args) s += v;

assertEq(s, 'abc');
// Debugger.Object.prototype.getErrorMessageName returns the error message name
// associated with some error object.

var g = newGlobal();
var dbg = new Debugger();
var gw = dbg.addDebuggee(g);

assertEq(gw.executeInGlobal("(42).toString(0)").throw.errorMessageName, "JSMSG_BAD_RADIX");

// Custom errors have no error message name.
assertEq(gw.executeInGlobal("throw new Error()").throw.errorMessageName, undefined);

// Ensure that the method works across globals.
g.eval(`var g = newGlobal();
        g.eval('var err; try { (42).toString(0); } catch (e) { err = e; }');
        var err2 = g.err;`);
assertEq(gw.executeInGlobal("throw err2").throw.errorMessageName, "JSMSG_BAD_RADIX");

// Ensure that non-error objects return undefined.
const Args = [
    "1",
    "'blah'",
    "({})",
    "[]",
    "() => 1"
]

for (let arg of Args)
    assertEq(gw.executeInGlobal(`${arg}`).return.errorMessageName, undefined);

vs

var g = newGlobal();

var dbg = new Debugger();

var gw = dbg.addDebuggee(g);

assertEq(gw.executeInGlobal("(42).toString(0)").throw.errorMessageName, "JSMSG_BAD_RADIX");

assertEq(gw.executeInGlobal("throw new Error()").throw.errorMessageName, undefined);

g.eval(`var g = newGlobal();
        g.eval('var err; try { (42).toString(0); } catch (e) { err = e; }');
        var err2 = g.err;`);

assertEq(gw.executeInGlobal("throw err2").throw.errorMessageName, "JSMSG_BAD_RADIX");

const Args = ["1", "'blah'", "({})", "[]", "() => 1",];

for (arg of Args) assertEq(gw.executeInGlobal(`${arg}`).return.errorMessageName, undefined);
// Using shift to cut values out of an array does not change the next index of an existing iterator.

var a = [1, 2, 3, 4, 5, 6, 7, 8];
var s = '';
for (var v of a) {
    s += v;
    a.shift();
}
assertEq(s, '1357');

vs

var a = [1, 2, 3, 4, 5, 6, 7, 8,];

var s = '';

for (v of a) {
    s += v;

    a.shift();
}

assertEq(s, '1357');
// Debugger should be notified of scripts created with ExecuteInGlobalAndReturnScope.

var g = newGlobal();
var g2 = newGlobal();
var dbg = new Debugger(g, g2);
var log = '';
var canary = 42;

dbg.onNewScript = function (evalScript) {
  log += 'e';

  dbg.onNewScript = function (clonedScript) {
    log += 'c';
    clonedScript.setBreakpoint(0, {
      hit(frame) {
        log += 'b';
        assertEq(frame.script, clonedScript);
      }
    });
  };
};

dbg.onDebuggerStatement = function (frame) {
  log += 'd';
};

assertEq(log, '');
var evalScopes = g.evalReturningScope("canary = 'dead'; let lex = 42; debugger; // nee", g2);
assertEq(log, 'ecbd');
assertEq(canary, 42);
assertEq(evalScopes.vars.canary, 'dead');
assertEq(evalScopes.lexicals.lex, 42);

vs

var g = newGlobal();

var g2 = newGlobal();

var dbg = new Debugger(g, g2);

var log = '';

var canary = 42;

dbg.onNewScript = (function(evalScript) {
    log += 'e';
    dbg.onNewScript = function(clonedScript) {
        log += 'c';
        clonedScript.setBreakpoint(0, {
            hit: function(frame) {
                log += 'b';
                assertEq(frame.script, clonedScript);
            },
        });
    };
});

dbg.onDebuggerStatement = (function(frame) {
    log += 'd';
});

assertEq(log, '');

var evalScopes = g.evalReturningScope("canary = 'dead'; let lex = 42; debugger; // nee", g2);

assertEq(log, 'ecbd');

assertEq(canary, 42);

assertEq(evalScopes.vars.canary, 'dead');

assertEq(evalScopes.lexicals.lex, 42);
// for-of on a proxy causes a predictable sequence of trap calls.

load(libdir + "iteration.js");

var s = '';

var i = 0;
var next_fn = new Proxy(function() {}, {
    apply() {
        s += "n";
        if (i == 3)
            return { value: undefined, done: true };
        return { value: i++, done: false };
    }
});

var it = new Proxy({}, {
    get(target, property, receiver) {
        assertEq(property, "next");
        s += "N";
        return next_fn;
    }
});

var iterator_fn = new Proxy(function() {}, {
    apply() {
        s += 'i';
        return it;
    }
});

var obj = new Proxy({}, {
    get: function (receiver, name) {
        assertEq(name, Symbol.iterator);
        s += "I";
        return iterator_fn;
    }
});

for (var v of obj)
    s += v;

assertEq(s, 'IiNn0n1n2n');

vs

load(libdir + "iteration.js");

var s = '';

var i = 0;

var next_fn = new Proxy((function() { }), ({
    apply: (function() {
        s += "n";
        if (i == 3) return {
            value: undefined,
            done: true,
        };

        return {
            value: i++,
            done: false,
        };
    }),
}));

var it = new Proxy(({}), ({
    get: (function(target, property, receiver) {
        assertEq(property, "next");
        s += "N";
        return next_fn;
    }),
}));

var iterator_fn = new Proxy((function() { }), ({
    apply: (function() {
        s += 'i';
        return it;
    }),
}));

var obj = new Proxy(({}), ({
    get: (function(receiver, name) {
        assertEq(name, Symbol.iterator);
        s += "I";
        return iterator_fn;
    }),
}));

for (v of obj) s += v;

assertEq(s, 'IiNn0n1n2n');
// for-of consults Array.prototype when it encounters a hole.

Array.prototype[1] = 'peek';
var log = [];
for (var x of [0, , 2, 3])
    log.push(x);
assertEq(log[1], 'peek');
assertEq(log.join(), "0,peek,2,3");

vs

Array.prototype[1] = 'peek';

var log = [];

for (x of [0,, 2, 3,]) log.push(x);

assertEq(log[1], 'peek');

assertEq(log.join(), "0,peek,2,3");
// Funny case that looks kind of like default arguments isn't.

var f = (msg='hi', w=window => w.alert(a, b));  // sequence expression
assertEq(msg, 'hi');
assertEq(typeof w, 'function');
assertEq(f, w);

vs

var f = msg = 'hi', w = window => w.alert(a, b);

assertEq(msg, 'hi');

assertEq(typeof w, 'function');

assertEq(f, w);
// Iterating over non-iterable values throws a TypeError.

load(libdir + "asserts.js");

var misc = [
    {}, {x: 1}, Math, isNaN,
    Object.create(null),
    null, undefined,
    true, 0, 3.1416,
    new Boolean(true), new Number(0),
    {iterator: function () { return undefined; }},
    {iterator: function () { return null; }},
    {iterator: function () { return true; }},
    {iterator: function () { return 17; }},
];

for (var i = 0; i < misc.length; i++) {
    let v = misc[i];
    var testfn = function () {
        for (var _ of v)
            throw 'FAIL';
        throw 'BAD';
    };
    assertThrowsInstanceOf(testfn, TypeError);
}

vs

load(libdir + "asserts.js");

var misc = [({}), ({
    x: 1,
}), Math, isNaN, Object.create(null), null, undefined, true, 0, 3.1416, new Boolean(true), new Number(0), ({
    iterator: (function() {
        return undefined;
    }),
}), ({
    iterator: (function() {
        return null;
    }),
}), ({
    iterator: (function() {
        return true;
    }),
}), ({
    iterator: (function() {
        return 17;
    }),
}),];

for (let i = 0;i < misc.length;i++) {
    let v = misc[i];

    var testfn = function() {
        for (_ of v) throw 'FAIL';
        throw 'BAD';
    };

    assertThrowsInstanceOf(testfn, TypeError);
}
// Control can exit a for-of loop via return.

function f() {
    for (var a of [1, 2, 3]) {
        for (var b of [1, 2, 3]) {
            for (var c of [1, 2, 3]) {
                if (a !== b && b !== c && c !== a)
                    return "" + a + b + c;
            }
        }
    }
}

assertEq(f(), "123");

vs

function f() {
    for (a of [1, 2, 3,]) {
        for (b of [1, 2, 3,]) {
            for (c of [1, 2, 3,]) {
                if (a !== b && b !== c && c !== a) return "" + a + b + c;

            }
        }
    }
}

assertEq(f(), "123");
// MagicNumber = 0x6d736100;
const magic0 = 0x00;  // '\0'
const magic1 = 0x61;  // 'a'
const magic2 = 0x73;  // 's'
const magic3 = 0x6d;  // 'm'

// EncodingVersion
const encodingVersion = 0x1;
const ver0 = (encodingVersion >>>  0) & 0xff;
const ver1 = (encodingVersion >>>  8) & 0xff;
const ver2 = (encodingVersion >>> 16) & 0xff;
const ver3 = (encodingVersion >>> 24) & 0xff;

// Section opcodes
const userDefinedId    = 0;
const typeId           = 1;
const importId         = 2;
const functionId       = 3;
const tableId          = 4;
const memoryId         = 5;
const globalId         = 6;
const exportId         = 7;
const startId          = 8;
const elemId           = 9;
const codeId           = 10;
const dataId           = 11;
const gcFeatureOptInId = 42;

// User-defined section names
const nameName         = "name";

// Name section name types
const nameTypeModule   = 0;
const nameTypeFunction = 1;
const nameTypeLocal    = 2;

// Type codes
const I32Code          = 0x7f;
const I64Code          = 0x7e;
const F32Code          = 0x7d;
const F64Code          = 0x7c;
const AnyFuncCode      = 0x70;
const AnyrefCode       = 0x6f;
const RefCode          = 0x6e;
const FuncCode         = 0x60;
const VoidCode         = 0x40;

// Opcodes
const UnreachableCode  = 0x00
const BlockCode        = 0x02;
const EndCode          = 0x0b;
const CallCode         = 0x10;
const CallIndirectCode = 0x11;
const DropCode         = 0x1a;
const SelectCode       = 0x1b;
const I32Load          = 0x28;
const I64Load          = 0x29;
const F32Load          = 0x2a;
const F64Load          = 0x2b;
const I32Load8S        = 0x2c;
const I32Load8U        = 0x2d;
const I32Load16S       = 0x2e;
const I32Load16U       = 0x2f;
const I64Load8S        = 0x30;
const I64Load8U        = 0x31;
const I64Load16S       = 0x32;
const I64Load16U       = 0x33;
const I64Load32S       = 0x34;
const I64Load32U       = 0x35;
const I32Store         = 0x36;
const I64Store         = 0x37;
const F32Store         = 0x38;
const F64Store         = 0x39;
const I32Store8        = 0x3a;
const I32Store16       = 0x3b;
const I64Store8        = 0x3c;
const I64Store16       = 0x3d;
const I64Store32       = 0x3e;
const GrowMemoryCode   = 0x40;
const I32ConstCode     = 0x41;
const I64ConstCode     = 0x42;
const F32ConstCode     = 0x43;
const F64ConstCode     = 0x44;
const I32AddCode       = 0x6a;
const I32DivSCode      = 0x6d;
const I32DivUCode      = 0x6e;
const I32RemSCode      = 0x6f;
const I32RemUCode      = 0x70;
const I32TruncSF32Code = 0xa8;
const I32TruncUF32Code = 0xa9;
const I32TruncSF64Code = 0xaa;
const I32TruncUF64Code = 0xab;
const I64TruncSF32Code = 0xae;
const I64TruncUF32Code = 0xaf;
const I64TruncSF64Code = 0xb0;
const I64TruncUF64Code = 0xb1;
const I64DivSCode      = 0x7f;
const I64DivUCode      = 0x80;
const I64RemSCode      = 0x81;
const I64RemUCode      = 0x82;
const RefNull          = 0xd0;

const FirstInvalidOpcode = 0xc5;
const LastInvalidOpcode = 0xfb;
const MiscPrefix = 0xfc;
const SimdPrefix = 0xfd;
const ThreadPrefix = 0xfe;
const MozPrefix = 0xff;

// Secondary opcode bytes for misc prefix
const StructNew = 0x50;         // UNOFFICIAL
const StructGet = 0x51;         // UNOFFICIAL
const StructSet = 0x52;         // UNOFFICIAL
const StructNarrow = 0x53;      // UNOFFICIAL

// DefinitionKind
const FunctionCode     = 0x00;
const TableCode        = 0x01;
const MemoryCode       = 0x02;
const GlobalCode       = 0x03;

// ResizableFlags
const HasMaximumFlag   = 0x1;

function toU8(array) {
    for (let b of array)
        assertEq(b < 256, true);
    return Uint8Array.from(array);
}

function varU32(u32) {
    assertEq(u32 >= 0, true);
    assertEq(u32 < Math.pow(2,32), true);
    var bytes = [];
    do {
        var byte = u32 & 0x7f;
        u32 >>>= 7;
        if (u32 != 0)
            byte |= 0x80;
        bytes.push(byte);
    } while (u32 != 0);
    return bytes;
}

function varS32(s32) {
    assertEq(s32 >= -Math.pow(2,31), true);
    assertEq(s32 < Math.pow(2,31), true);
    var bytes = [];
    do {
        var byte = s32 & 0x7f;
        s32 >>= 7;
        if (s32 != 0 && s32 != -1)
            byte |= 0x80;
        bytes.push(byte);
    } while (s32 != 0 && s32 != -1);
    return bytes;
}

function moduleHeaderThen(...rest) {
    return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest];
}

function string(name) {
    var nameBytes = name.split('').map(c => {
        var code = c.charCodeAt(0);
        assertEq(code < 128, true); // TODO
        return code
    });
    return varU32(nameBytes.length).concat(nameBytes);
}

function encodedString(name, len) {
    var name = unescape(encodeURIComponent(name)); // break into string of utf8 code points
    var nameBytes = name.split('').map(c => c.charCodeAt(0)); // map to array of numbers
    return varU32(len === undefined ? nameBytes.length : len).concat(nameBytes);
}

function moduleWithSections(sectionArray) {
    var bytes = moduleHeaderThen();
    for (let section of sectionArray) {
        bytes.push(section.name);
        bytes.push(...varU32(section.body.length));
        bytes.push(...section.body);
    }
    return toU8(bytes);
}

function gcFeatureOptInSection(version) {
    return { name: gcFeatureOptInId, body: [ version & 0x7F ] }
}

function sigSection(sigs) {
    var body = [];
    body.push(...varU32(sigs.length));
    for (let sig of sigs) {
        body.push(...varU32(FuncCode));
        body.push(...varU32(sig.args.length));
        for (let arg of sig.args)
            body.push(...varU32(arg));
        body.push(...varU32(sig.ret == VoidCode ? 0 : 1));
        if (sig.ret != VoidCode)
            body.push(...varU32(sig.ret));
    }
    return { name: typeId, body };
}

function declSection(decls) {
    var body = [];
    body.push(...varU32(decls.length));
    for (let decl of decls)
        body.push(...varU32(decl));
    return { name: functionId, body };
}

function funcBody(func, withEndCode=true) {
    var body = varU32(func.locals.length);
    for (let local of func.locals)
        body.push(...varU32(local));
    body = body.concat(...func.body);
    if (withEndCode)
        body.push(EndCode);
    body.splice(0, 0, ...varU32(body.length));
    return body;
}

function bodySection(bodies) {
    var body = varU32(bodies.length).concat(...bodies);
    return { name: codeId, body };
}

function importSection(imports) {
    var body = [];
    body.push(...varU32(imports.length));
    for (let imp of imports) {
        body.push(...string(imp.module));
        body.push(...string(imp.func));
        body.push(...varU32(FunctionCode));
        body.push(...varU32(imp.sigIndex));
    }
    return { name: importId, body };
}

function exportSection(exports) {
    var body = [];
    body.push(...varU32(exports.length));
    for (let exp of exports) {
        body.push(...string(exp.name));
        body.push(...varU32(FunctionCode));
        body.push(...varU32(exp.funcIndex));
    }
    return { name: exportId, body };
}

function tableSection(initialSize) {
    var body = [];
    body.push(...varU32(1));           // number of tables
    body.push(...varU32(AnyFuncCode));
    body.push(...varU32(0x0));         // for now, no maximum
    body.push(...varU32(initialSize));
    return { name: tableId, body };
}

function memorySection(initialSize) {
    var body = [];
    body.push(...varU32(1));           // number of memories
    body.push(...varU32(0x0));         // for now, no maximum
    body.push(...varU32(initialSize));
    return { name: memoryId, body };
}

function dataSection(segmentArrays) {
    var body = [];
    body.push(...varU32(segmentArrays.length));
    for (let array of segmentArrays) {
        body.push(...varU32(0)); // table index
        body.push(...varU32(I32ConstCode));
        body.push(...varS32(array.offset));
        body.push(...varU32(EndCode));
        body.push(...varU32(array.elems.length));
        for (let elem of array.elems)
            body.push(...varU32(elem));
    }
    return { name: dataId, body };
}

function elemSection(elemArrays) {
    var body = [];
    body.push(...varU32(elemArrays.length));
    for (let array of elemArrays) {
        body.push(...varU32(0)); // table index
        body.push(...varU32(I32ConstCode));
        body.push(...varS32(array.offset));
        body.push(...varU32(EndCode));
        body.push(...varU32(array.elems.length));
        for (let elem of array.elems)
            body.push(...varU32(elem));
    }
    return { name: elemId, body };
}

function moduleNameSubsection(moduleName) {
    var body = [];
    body.push(...varU32(nameTypeModule));

    var subsection = encodedString(moduleName);
    body.push(...varU32(subsection.length));
    body.push(...subsection);

    return body;
}

function funcNameSubsection(funcNames) {
    var body = [];
    body.push(...varU32(nameTypeFunction));

    var subsection = varU32(funcNames.length);

    var funcIndex = 0;
    for (let f of funcNames) {
        subsection.push(...varU32(f.index ? f.index : funcIndex));
        subsection.push(...encodedString(f.name, f.nameLen));
        funcIndex++;
    }

    body.push(...varU32(subsection.length));
    body.push(...subsection);
    return body;
}

function nameSection(subsections) {
    var body = [];
    body.push(...string(nameName));

    for (let ss of subsections)
        body.push(...ss);

    return { name: userDefinedId, body };
}

function customSection(name, ...body) {
    return { name: userDefinedId, body: [...string(name), ...body] };
}

function tableSection0() {
    var body = [];
    body.push(...varU32(0));           // number of tables
    return { name: tableId, body };
}

function memorySection0() {
    var body = [];
    body.push(...varU32(0));           // number of memories
    return { name: memoryId, body };
}

vs

const magic0 = 0x00;

const magic1 = 0x61;

const magic2 = 0x73;

const magic3 = 0x6d;

const encodingVersion = 0x1;

const ver0 = encodingVersion >>> 0 & 0xff;

const ver1 = encodingVersion >>> 8 & 0xff;

const ver2 = encodingVersion >>> 16 & 0xff;

const ver3 = encodingVersion >>> 24 & 0xff;

const userDefinedId = 0;

const typeId = 1;

const importId = 2;

const functionId = 3;

const tableId = 4;

const memoryId = 5;

const globalId = 6;

const exportId = 7;

const startId = 8;

const elemId = 9;

const codeId = 10;

const dataId = 11;

const gcFeatureOptInId = 42;

const nameName = "name";

const nameTypeModule = 0;

const nameTypeFunction = 1;

const nameTypeLocal = 2;

const I32Code = 0x7f;

const I64Code = 0x7e;

const F32Code = 0x7d;

const F64Code = 0x7c;

const AnyFuncCode = 0x70;

const AnyrefCode = 0x6f;

const RefCode = 0x6e;

const FuncCode = 0x60;

const VoidCode = 0x40;

const UnreachableCode = 0x00;

const BlockCode = 0x02;

const EndCode = 0x0b;

const CallCode = 0x10;

const CallIndirectCode = 0x11;

const DropCode = 0x1a;

const SelectCode = 0x1b;

const I32Load = 0x28;

const I64Load = 0x29;

const F32Load = 0x2a;

const F64Load = 0x2b;

const I32Load8S = 0x2c;

const I32Load8U = 0x2d;

const I32Load16S = 0x2e;

const I32Load16U = 0x2f;

const I64Load8S = 0x30;

const I64Load8U = 0x31;

const I64Load16S = 0x32;

const I64Load16U = 0x33;

const I64Load32S = 0x34;

const I64Load32U = 0x35;

const I32Store = 0x36;

const I64Store = 0x37;

const F32Store = 0x38;

const F64Store = 0x39;

const I32Store8 = 0x3a;

const I32Store16 = 0x3b;

const I64Store8 = 0x3c;

const I64Store16 = 0x3d;

const I64Store32 = 0x3e;

const GrowMemoryCode = 0x40;

const I32ConstCode = 0x41;

const I64ConstCode = 0x42;

const F32ConstCode = 0x43;

const F64ConstCode = 0x44;

const I32AddCode = 0x6a;

const I32DivSCode = 0x6d;

const I32DivUCode = 0x6e;

const I32RemSCode = 0x6f;

const I32RemUCode = 0x70;

const I32TruncSF32Code = 0xa8;

const I32TruncUF32Code = 0xa9;

const I32TruncSF64Code = 0xaa;

const I32TruncUF64Code = 0xab;

const I64TruncSF32Code = 0xae;

const I64TruncUF32Code = 0xaf;

const I64TruncSF64Code = 0xb0;

const I64TruncUF64Code = 0xb1;

const I64DivSCode = 0x7f;

const I64DivUCode = 0x80;

const I64RemSCode = 0x81;

const I64RemUCode = 0x82;

const RefNull = 0xd0;

const FirstInvalidOpcode = 0xc5;

const LastInvalidOpcode = 0xfb;

const MiscPrefix = 0xfc;

const SimdPrefix = 0xfd;

const ThreadPrefix = 0xfe;

const MozPrefix = 0xff;

const StructNew = 0x50;

const StructGet = 0x51;

const StructSet = 0x52;

const StructNarrow = 0x53;

const FunctionCode = 0x00;

const TableCode = 0x01;

const MemoryCode = 0x02;

const GlobalCode = 0x03;

const HasMaximumFlag = 0x1;

function toU8(array) {
    for (b of array) assertEq(b < 256, true);
    return Uint8Array.from(array);
}

function varU32(u32) {
    assertEq(u32 >= 0, true);
    assertEq(u32 < Math.pow(2, 32), true);
    var bytes = [];
    do {
        var byte = u32 & 0x7f;

        u32 >>>= 7;

        if (u32 != 0) byte |= 0x80;


        bytes.push(byte);
    } while (u32 != 0);
    ;
    return bytes;
}

function varS32(s32) {
    assertEq(s32 >= -Math.pow(2, 31), true);
    assertEq(s32 < Math.pow(2, 31), true);
    var bytes = [];
    do {
        var byte = s32 & 0x7f;

        s32 >>= 7;

        if (s32 != 0 && s32 != -1) byte |= 0x80;


        bytes.push(byte);
    } while (s32 != 0 && s32 != -1);
    ;
    return bytes;
}

function moduleHeaderThen(rest) {
    return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest,];
}

function string(name) {
    var nameBytes = name.split('').map(c => {
        var code = c.charCodeAt(0);
        assertEq(code < 128, true);
        return code;
    });
    return varU32(nameBytes.length).concat(nameBytes);
}

function encodedString(name, len) {
    var name = unescape(encodeURIComponent(name));
    var nameBytes = name.split('').map(c => c.charCodeAt(0));
    return varU32(len === undefined ? nameBytes.length : len).concat(nameBytes);
}

function moduleWithSections(sectionArray) {
    var bytes = moduleHeaderThen();
    for (section of sectionArray) {
        bytes.push(section.name);

        bytes.push(...varU32(section.body.length));

        bytes.push(...section.body);
    }
    return toU8(bytes);
}

function gcFeatureOptInSection(version) {
    return {
        name: gcFeatureOptInId,
        body: [version & 0x7F,],
    };
}

function sigSection(sigs) {
    var body = [];
    body.push(...varU32(sigs.length));
    for (sig of sigs) {
        body.push(...varU32(FuncCode));

        body.push(...varU32(sig.args.length));

        for (arg of sig.args) body.push(...varU32(arg));

        body.push(...varU32(sig.ret == VoidCode ? 0 : 1));

        if (sig.ret != VoidCode) body.push(...varU32(sig.ret));

    }
    return {
        name: typeId,
        body,
    };
}

function declSection(decls) {
    var body = [];
    body.push(...varU32(decls.length));
    for (decl of decls) body.push(...varU32(decl));
    return {
        name: functionId,
        body,
    };
}

function funcBody(func, withEndCode = true) {
    var body = varU32(func.locals.length);
    for (local of func.locals) body.push(...varU32(local));
    body = body.concat(...func.body);
    if (withEndCode) body.push(EndCode);

    body.splice(0, 0, ...varU32(body.length));
    return body;
}

function bodySection(bodies) {
    var body = varU32(bodies.length).concat(...bodies);
    return {
        name: codeId,
        body,
    };
}

function importSection(imports) {
    var body = [];
    body.push(...varU32(imports.length));
    for (imp of imports) {
        body.push(...string(imp.module));

        body.push(...string(imp.func));

        body.push(...varU32(FunctionCode));

        body.push(...varU32(imp.sigIndex));
    }
    return {
        name: importId,
        body,
    };
}

function exportSection(exports) {
    var body = [];
    body.push(...varU32(exports.length));
    for (exp of exports) {
        body.push(...string(exp.name));

        body.push(...varU32(FunctionCode));

        body.push(...varU32(exp.funcIndex));
    }
    return {
        name: exportId,
        body,
    };
}

function tableSection(initialSize) {
    var body = [];
    body.push(...varU32(1));
    body.push(...varU32(AnyFuncCode));
    body.push(...varU32(0x0));
    body.push(...varU32(initialSize));
    return {
        name: tableId,
        body,
    };
}

function memorySection(initialSize) {
    var body = [];
    body.push(...varU32(1));
    body.push(...varU32(0x0));
    body.push(...varU32(initialSize));
    return {
        name: memoryId,
        body,
    };
}

function dataSection(segmentArrays) {
    var body = [];
    body.push(...varU32(segmentArrays.length));
    for (array of segmentArrays) {
        body.push(...varU32(0));

        body.push(...varU32(I32ConstCode));

        body.push(...varS32(array.offset));

        body.push(...varU32(EndCode));

        body.push(...varU32(array.elems.length));

        for (elem of array.elems) body.push(...varU32(elem));
    }
    return {
        name: dataId,
        body,
    };
}

function elemSection(elemArrays) {
    var body = [];
    body.push(...varU32(elemArrays.length));
    for (array of elemArrays) {
        body.push(...varU32(0));

        body.push(...varU32(I32ConstCode));

        body.push(...varS32(array.offset));

        body.push(...varU32(EndCode));

        body.push(...varU32(array.elems.length));

        for (elem of array.elems) body.push(...varU32(elem));
    }
    return {
        name: elemId,
        body,
    };
}

function moduleNameSubsection(moduleName) {
    var body = [];
    body.push(...varU32(nameTypeModule));
    var subsection = encodedString(moduleName);
    body.push(...varU32(subsection.length));
    body.push(...subsection);
    return body;
}

function funcNameSubsection(funcNames) {
    var body = [];
    body.push(...varU32(nameTypeFunction));
    var subsection = varU32(funcNames.length);
    var funcIndex = 0;
    for (f of funcNames) {
        subsection.push(...varU32(f.index ? f.index : funcIndex));

        subsection.push(...encodedString(f.name, f.nameLen));

        funcIndex++;
    }
    body.push(...varU32(subsection.length));
    body.push(...subsection);
    return body;
}

function nameSection(subsections) {
    var body = [];
    body.push(...string(nameName));
    for (ss of subsections) body.push(...ss);
    return {
        name: userDefinedId,
        body,
    };
}

function customSection(name, body) {
    return {
        name: userDefinedId,
        body: [...string(name), ...body,],
    };
}

function tableSection0() {
    var body = [];
    body.push(...varU32(0));
    return {
        name: tableId,
        body,
    };
}

function memorySection0() {
    var body = [];
    body.push(...varU32(0));
    return {
        name: memoryId,
        body,
    };
}
// Giving an Array an own .iterator property affects for-of.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

var a = [];
a[Symbol.iterator] = function* () {
    yield 'o';
    yield 'k';
};
var s = '';
for (var v of a)
    s += v;
assertEq(s, 'ok');

a[Symbol.iterator] = undefined;
assertThrowsInstanceOf(function () { for (var v of a) ; }, TypeError);

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

var a = [];

a[Symbol.iterator] = (function*() {
    yield 'o';
    yield 'k';
});

var s = '';

for (v of a) s += v;

assertEq(s, 'ok');

a[Symbol.iterator] = undefined;

assertThrowsInstanceOf((function() {
    for (v of a) ;
}), TypeError);
// A for-of loop over an array does not take a snapshot of the array elements.
// Instead, each time the loop needs an element from the array, it gets its current value.

var a = [3, 5, 5, 4, 0, 5];
var s = '';
for (var i of a) {
    s += i;
    a[i] = 'X';
}
assertEq(s, '355X0X');

vs

var a = [3, 5, 5, 4, 0, 5,];

var s = '';

for (i of a) {
    s += i;

    a[i] = 'X';
}

assertEq(s, '355X0X');
// Breaking out of a for-of loop over a generator-iterator closes the generator.

load(libdir + "iteration.js");

function* range(n) {
    for (var i = 0; i < n; i++)
        yield i;
}

var r = range(10);
var s = '';
for (var x of r) {
    s += x;
    if (x == 4)
        break;
}
s += '/';
for (var y of r)
    s += y;
assertEq(s, '01234/');

vs

load(libdir + "iteration.js");

function *range(n) {
    for (let i = 0;i < n;i++) yield i;
}

var r = range(10);

var s = '';

for (x of r) {
    s += x;

    if (x == 4) break;

}

s += '/';

for (y of r) s += y;

assertEq(s, '01234/');
// Test drainAllocationsLog() and byte sizes.

const root = newGlobal();
const dbg = new Debugger();
const wrappedRoot = dbg.addDebuggee(root);

root.eval(
  `
  function AsmModule(stdlib, foreign, heap) {
    "use asm";

    function test() {
      return 5|0;
    }

    return { test: test };
  }
  const buf = new ArrayBuffer(1024*8);

  function Ctor() {}
  this.tests = [
    { name: "new UInt8Array(256)", fn: () => new Uint8Array(256)         },
    { name: "arguments",           fn: function () { return arguments; } },
    { name: "asm.js module",       fn: () => AsmModule(this, {}, buf)    },
    { name: "/2manyproblemz/g",    fn: () => /2manyproblemz/g            },
    { name: "iterator",            fn: () => [1,2,3][Symbol.iterator]()  },
    { name: "Error()",             fn: () => Error()                     },
    { name: "new Ctor",            fn: () => new Ctor                    },
    { name: "{}",                  fn: () => ({})                        },
    { name: "new Date",            fn: () => new Date                    },
    { name: "[1,2,3]",             fn: () => [1,2,3]                     },
  ];
  `
);

for (let { name, fn } of root.tests) {
  print("Test: " + name);

  dbg.memory.trackingAllocationSites = true;

  fn();

  let entries = dbg.memory.drainAllocationsLog();

  for (let {size} of entries) {
    print("  " + size + " bytes");
    // We should get some kind of byte size. We aren't testing that in depth
    // here, it is tested pretty thoroughly in
    // js/src/jit-test/tests/heap-analysis/byteSize-of-object.js.
    assertEq(typeof size, "number");
    assertEq(size > 0, true);
  }

  dbg.memory.trackingAllocationSites = false;
}

vs

const root = newGlobal();

const dbg = new Debugger();

const wrappedRoot = dbg.addDebuggee(root);

root.eval(`
  function AsmModule(stdlib, foreign, heap) {
    "use asm";

    function test() {
      return 5|0;
    }

    return { test: test };
  }
  const buf = new ArrayBuffer(1024*8);

  function Ctor() {}
  this.tests = [
    { name: "new UInt8Array(256)", fn: () => new Uint8Array(256)         },
    { name: "arguments",           fn: function () { return arguments; } },
    { name: "asm.js module",       fn: () => AsmModule(this, {}, buf)    },
    { name: "/2manyproblemz/g",    fn: () => /2manyproblemz/g            },
    { name: "iterator",            fn: () => [1,2,3][Symbol.iterator]()  },
    { name: "Error()",             fn: () => Error()                     },
    { name: "new Ctor",            fn: () => new Ctor                    },
    { name: "{}",                  fn: () => ({})                        },
    { name: "new Date",            fn: () => new Date                    },
    { name: "[1,2,3]",             fn: () => [1,2,3]                     },
  ];
  `);

for ({name, fn,} of root.tests) {
    print("Test: " + name);

    dbg.memory.trackingAllocationSites = true;

    fn();

    let entries = dbg.memory.drainAllocationsLog();

    for ({size,    } of entries) {
        print("  " + size + " bytes");

        assertEq(typeof size, "number");

        assertEq(size > 0, true);
    }

    dbg.memory.trackingAllocationSites = false;
}
// frame.onStep can coexist with breakpoints.

var g = newGlobal();
var dbg = Debugger(g);
var log = '';
dbg.onEnterFrame = function (frame) {
    var handler = {hit: function () { log += 'B'; }};
    var lines = frame.script.getAllOffsets();
    for (var line in lines) {
        line = Number(line);
        var offs = lines[line];
        for (var i = 0; i < offs.length; i++)
            frame.script.setBreakpoint(offs[i], handler);
    }

    frame.onStep = function () { log += 's'; };
};

g.eval("one = 1;\n" +
       "two = 2;\n" +
       "three = 3;\n" +
       "four = 4;\n");
assertEq(g.four, 4);

// Breakpoints hit on all four lines, plus the final line.
assertEq(log.replace(/[^B]/g, ''), 'BBBBB');

// onStep was called between each pair of breakpoints.
assertEq(/BB/.exec(log), null);

vs

var g = newGlobal();

var dbg = Debugger(g);

var log = '';

dbg.onEnterFrame = (function(frame) {
    var handler = {
        hit: function() {
            log += 'B';
        },
    };
    var lines = frame.script.getAllOffsets();
    for (line in lines) {
        line = Number(line);

        var offs = lines[line];

        for (let i = 0;i < offs.length;i++) frame.script.setBreakpoint(offs[i], handler);
    }
    frame.onStep = function() {
        log += 's';
    };
});

g.eval("one = 1;\n" + "two = 2;\n" + "three = 3;\n" + "four = 4;\n");

assertEq(g.four, 4);

assertEq(log.replace(/[^B]/g, ''), 'BBBBB');

assertEq(/BB/.exec(log), null);
// |jit-test| error: TypeError
(function() {
  for (let z in [true]) {
    (new(eval("for(l in[0,0,0,0]){}"))
     (((function f(a, b) {
      if (a.length == b) {
        return (z)
      }
      f(a, b + 1)
    })([,,], 0)), []))
  }
})()

vs

(function() {
    for (z in [true,]) {
        new eval("for(l in[0,0,0,0]){}")(function f(a, b) {
            if (a.length == b) {
                return z;
            }
            f(a, b + 1);
        }([,,], 0), []);
    }
})();
// Replacing Array.prototype.iterator with a generator affects for-of behavior.

load(libdir + "iteration.js");

Array.prototype[Symbol.iterator] = function* () {
    for (var i = this.length; --i >= 0; )
        yield this[i];
};

var s = '';
for (var v of ['a', 'b', 'c', 'd'])
    s += v;
assertEq(s, 'dcba');

vs

load(libdir + "iteration.js");

Array.prototype[Symbol.iterator] = (function*() {
    for (let i = this.length;--i >= 0;) yield this[i];
});

var s = '';

for (v of ['a', 'b', 'c', 'd',]) s += v;

assertEq(s, 'dcba');
// Array.prototype.iterator applied to undefined or null throws directly.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

for (var v of [undefined, null]) {
    // ES6 draft 2013-09-05 section 22.1.5.1.
    assertThrowsInstanceOf(function () { Array.prototype[Symbol.iterator].call(v); }, TypeError);
    assertThrowsInstanceOf(function () { Array.prototype.keys.call(v); }, TypeError);
    assertThrowsInstanceOf(function () { Array.prototype.entries.call(v); }, TypeError);
}

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

for (v of [undefined, null,]) {
    assertThrowsInstanceOf(function() {
        Array.prototype[Symbol.iterator].call(v);
    }, TypeError);

    assertThrowsInstanceOf(function() {
        Array.prototype.keys.call(v);
    }, TypeError);

    assertThrowsInstanceOf(function() {
        Array.prototype.entries.call(v);
    }, TypeError);
}
// Slowifying an array while it is being iterated does not affect iteration.

var a = [9, 8, 7, 6, 5, 4, 3];
var log = '';
for (var x of a) {
    log += x;
    if (x === 6)
        a.slow = true;
}
assertEq(log, "9876543");

vs

var a = [9, 8, 7, 6, 5, 4, 3,];

var log = '';

for (x of a) {
    log += x;

    if (x === 6) a.slow = true;

}

assertEq(log, "9876543");
// tests calling script functions via Debugger.Object.prototype.setProperty
// to see if they trigger debugger traps
"use strict";

var global = newGlobal();
var dbg = new Debugger(global);
dbg.onDebuggerStatement = onDebuggerStatement;

let obj;
global.eval(`
const obj = {
    set prop(val) {
        debugger;
        this._prop = val;
    }
};

debugger;
`);


function onDebuggerStatement(frame) {
    dbg.onDebuggerStatement = onDebuggerStatementGetter;

    obj = frame.environment.getVariable("obj");
}

let debuggerRan = false;

assertEq(obj.setProperty("prop", 42).return, true);
assertEq(obj.getProperty("_prop").return, 42);
assertEq(debuggerRan, true);

function onDebuggerStatementGetter(frame) {
    debuggerRan = true;
}

vs

'use strict';

var global = newGlobal();

var dbg = new Debugger(global);

dbg.onDebuggerStatement = onDebuggerStatement;

let obj;

global.eval(`
const obj = {
    set prop(val) {
        debugger;
        this._prop = val;
    }
};

debugger;
`);

function onDebuggerStatement(frame) {
    dbg.onDebuggerStatement = onDebuggerStatementGetter;
    obj = frame.environment.getVariable("obj");
}

let debuggerRan = false;

assertEq(obj.setProperty("prop", 42).return, true);

assertEq(obj.getProperty("_prop").return, 42);

assertEq(debuggerRan, true);

function onDebuggerStatementGetter(frame) {
    debuggerRan = true;
}
// A break statement leaves only a single for-of loop.

var log = '';
for (var x of [1, 2, 3]) {
    for (var y of ['.', ':']) {
        log += x + y;
        break;
    }
}
assertEq(log, "1.2.3.");

vs

var log = '';

for (x of [1, 2, 3,]) {
    for (y of ['.', ':',]) {
        log += x + y;

        break;
    }
}

assertEq(log, "1.2.3.");
// Test for-of with iter.next and monkeypatching.

function* g(n) { for (var i=0; i<n; i++) yield i; }
var GeneratorObjectPrototype = Object.getPrototypeOf(g).prototype;
var GeneratorObjectPrototype_next = GeneratorObjectPrototype.next;

// Monkeypatch next on an iterator.
var inner = g(20);
var n = 0;
for (let x of inner) {
    assertEq(x, n++);
    if (n == 1) {
        inner.next = function() { throw 'not reached'; };
    }
}
assertEq(n, 20);

// Monkeypatch next on the prototype.
var inner = g(20);
var n = 0;
for (let x of inner) {
    assertEq(x, n++);
    if (n == 1) {
        GeneratorObjectPrototype.next = function() { throw 'not reached'; };
    }
}
assertEq(n, 20);

vs

function *g(n) {
    for (let i = 0;i < n;i++) yield i;
}

var GeneratorObjectPrototype = Object.getPrototypeOf(g).prototype;

var GeneratorObjectPrototype_next = GeneratorObjectPrototype.next;

var inner = g(20);

var n = 0;

for (x of inner) {
    assertEq(x, n++);

    if (n == 1) {
        inner.next = function() {
            throw 'not reached';
        };
    }
}

assertEq(n, 20);

var inner = g(20);

var n = 0;

for (x of inner) {
    assertEq(x, n++);

    if (n == 1) {
        GeneratorObjectPrototype.next = function() {
            throw 'not reached';
        };
    }
}

assertEq(n, 20);
// Deleting the .next method of an iterator in the middle of a for-of loop
// doesn't cause a TypeError at the next iteration.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

var iterProto = Object.getPrototypeOf([][Symbol.iterator]());
var s = '';
for (var v of ['duck', 'duck', 'duck', 'goose', 'and now you\'re it']) {
    s += v;
    if (v === 'goose')
        delete iterProto.next;
    s += '.';
}
assertEq(s, 'duck.duck.duck.goose.and now you\'re it.');

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

var iterProto = Object.getPrototypeOf([][Symbol.iterator]());

var s = '';

for (v of ['duck', 'duck', 'duck', 'goose', 'and now you\'re it',]) {
    s += v;

    if (v === 'goose') delete iterProto.next;


    s += '.';
}

assertEq(s, 'duck.duck.duck.goose.and now you\'re it.');
// for-of on an empty array does nothing.

for (var x of [])
    fail();

vs

for (x of []) fail();
function toLatin1(s) {
    assertEq(isLatin1(s), true);
    return s;
}
function testLastIndexOf() {
    var s1 = toLatin1("abcdefgh123456\u0081defg");
    var s2 = toLatin1("456\u0081de");

    // Latin1 + Latin1
    assertEq(s1.lastIndexOf(s1), 0);
    assertEq(s1.lastIndexOf(s2), 11);
    assertEq(s1.lastIndexOf(s2, 10), -1);
    assertEq(s2.lastIndexOf(s1), -1);

    // Latin1 + TwoByte
    assertEq(s1.lastIndexOf("abc\u1234"), -1);
    assertEq(s1.lastIndexOf("def\u1234".substring(0, 3)), 15);
    assertEq(s1.lastIndexOf("def\u1234".substring(0, 3), 9), 3);

    // TwoByte + Latin1
    var s3 = "123456\u0081defg\u1123a456\u0081defg";
    assertEq(isLatin1(s2), true);
    assertEq(s3.lastIndexOf(s2), 13);
    assertEq(s3.lastIndexOf(s2, 12), 3);
    assertEq(s3.lastIndexOf(toLatin1("defg7")), -1);

    // TwoByte + TwoByte
    assertEq(s3.lastIndexOf("\u1123a4"), 11);
    assertEq(s3.lastIndexOf("\u1123a4", 10), -1);
    assertEq(s3.lastIndexOf("\u1123a\u1098"), -1);
    assertEq(s3.lastIndexOf(s3), 0);
}
testLastIndexOf();

function testIndexOf() {
    var s1 = toLatin1("abcdefgh123456d\u00AAefghi");
    var s2 = toLatin1("456d\u00AA");

    // Latin1 + Latin1
    assertEq(s1.indexOf(s1), 0);
    assertEq(s1.indexOf(s2), 11);
    assertEq(s1.indexOf(s2, 12), -1);
    assertEq(s2.indexOf(s1), -1);

    // Latin1 + TwoByte
    assertEq(s1.indexOf("abc\u1234"), -1);
    assertEq(s1.indexOf("def\u1234".substring(0, 3)), 3);
    assertEq(s1.indexOf("d\u00AAef\u1234".substring(0, 3), 9), 14);

    // TwoByte + Latin1
    var s3 = "123456d\u00AAefg\u1123a456d\u00AAefg";
    assertEq(isLatin1(s2), true);
    assertEq(s3.indexOf(s2), 3);
    assertEq(s3.indexOf(s2, 11), 13);
    assertEq(s3.indexOf(toLatin1("d\u00AAefg7")), -1);

    // TwoByte + TwoByte
    assertEq(s3.indexOf("\u1123a4"), 11);
    assertEq(s3.indexOf("\u1123a4", 12), -1);
    assertEq(s3.indexOf("\u1123a\u1098"), -1);
    assertEq(s3.indexOf(s3), 0);
}
testIndexOf();

function testincludes() {
    var s1 = toLatin1("abcdefgh123456defghi\u00EEj");
    var s2 = toLatin1("456defghi\u00EE");

    // Latin1 + Latin1
    assertEq(s1.includes(s1), true);
    assertEq(s1.includes(s2), true);
    assertEq(s1.includes(s2, 12), false);
    assertEq(s2.includes(s1), false);

    // Latin1 + TwoByte
    assertEq(s1.includes("abc\u1234"), false);
    assertEq(s1.includes("def\u1234".substring(0, 3)), true);
    assertEq(s1.includes("def\u1234".substring(0, 3), 9), true);

    // TwoByte + Latin1
    var s3 = "123456defg\u1123a456defghi\u00EEj";
    assertEq(isLatin1(s2), true);
    assertEq(s3.includes(s2), true);
    assertEq(s3.includes(s2, 13), false);
    assertEq(s3.includes(toLatin1("defg8")), false);

    // TwoByte + TwoByte
    assertEq(s3.includes("\u1123a4"), true);
    assertEq(s3.includes("\u1123a4", 11), false);
    assertEq(s3.includes("\u1123a\u1098"), false);
    assertEq(s3.includes(s3), true);
}
testincludes();

function testIndexOfBMH() {
    // BoyerMooreHorspool algorithm is used for large strings.
    var s = "012345678901234567890123456789".repeat(20);
    var text = s + "abcdefghijklmnopqrst\u00C1uvwxyz";
    text.indexOf("333");

    var textL1 = toLatin1(text);
    var patL1 = toLatin1("cdefghijklmnopqrst\u00C1uvwx");

    // Latin1 + Latin1
    assertEq(textL1.indexOf(patL1), 602);
    assertEq(textL1.indexOf(patL1, 603), -1);
    assertEq(textL1.indexOf(textL1), 0);

    // Latin1 + TwoByte
    assertEq(textL1.indexOf("cdefghijklmnopqrst\u00C1uvwxy"), 602);
    assertEq(textL1.indexOf("cdefghijklmnopqrst\u00C1uvwxy", 603), -1);
    assertEq(textL1.indexOf("cdefghijklmnopqrst\u00C1uvwxy\uaa00", -1), -1);

    // TwoByte + Latin1
    var textTB = s + "abcdefghijklmnopqrst\u00C1uvwxyz\u1200";
    text.indexOf("333");
    assertEq(textTB.indexOf(patL1), 602);
    assertEq(textTB.indexOf(patL1, 603), -1);

    // TwoByte + TwoByte
    assertEq(textTB.indexOf("defghijklmnopqrst\u00C1uvwxyz\u1200"), 603);
    assertEq(textTB.indexOf("defghijklmnopqrst\u00C1uvwxyz\u1200", 604), -1);
    assertEq(textTB.indexOf("defghijklmnopqrst\u00C1uvwxyz\u1201"), -1);
}
testIndexOfBMH();

function testIndexOfLargePattern() {
    // If the pattern length > 128, memcmp is used (text length has to be < 512
    // or we'll use BoyerMooreHorspool). This is only valid if both
    // strings have the same encoding.
    var text = "012345678901234567890123456789".repeat(10) + "abcdefghijklmnopqrst\u00C1uvwxyz";
    text.indexOf("333"); // flatten
    var pat = "012345678901234567890123456789".repeat(5) + "abcdefghijklmnopqr";
    pat.indexOf("333"); // flatten

    // Latin1 + Latin1
    text = toLatin1(text);
    pat = toLatin1(pat);
    assertEq(text.indexOf(pat), 150);

    // Latin1 + TwoByte
    assertEq(text.indexOf(pat + "\u1200"), -1);
    assertEq(text.indexOf((pat + "\u1200").slice(0, -1)), 150);

    // TwoByte + Latin1
    text = text + "\u1100";
    assertEq(isLatin1(pat), true);
    assertEq(text.indexOf(pat), 150);

    // TwoByte + TwoByte
    pat = pat + "st\u00C1uvwxyz\u1100";
    assertEq(text.indexOf(pat), 150);
    assertEq(text.indexOf(pat + "\u2000"), -1);
}
testIndexOfLargePattern();

vs

function toLatin1(s) {
    assertEq(isLatin1(s), true);
    return s;
}

function testLastIndexOf() {
    var s1 = toLatin1("abcdefgh123456\u0081defg");
    var s2 = toLatin1("456\u0081de");
    assertEq(s1.lastIndexOf(s1), 0);
    assertEq(s1.lastIndexOf(s2), 11);
    assertEq(s1.lastIndexOf(s2, 10), -1);
    assertEq(s2.lastIndexOf(s1), -1);
    assertEq(s1.lastIndexOf("abc\u1234"), -1);
    assertEq(s1.lastIndexOf("def\u1234".substring(0, 3)), 15);
    assertEq(s1.lastIndexOf("def\u1234".substring(0, 3), 9), 3);
    var s3 = "123456\u0081defg\u1123a456\u0081defg";
    assertEq(isLatin1(s2), true);
    assertEq(s3.lastIndexOf(s2), 13);
    assertEq(s3.lastIndexOf(s2, 12), 3);
    assertEq(s3.lastIndexOf(toLatin1("defg7")), -1);
    assertEq(s3.lastIndexOf("\u1123a4"), 11);
    assertEq(s3.lastIndexOf("\u1123a4", 10), -1);
    assertEq(s3.lastIndexOf("\u1123a\u1098"), -1);
    assertEq(s3.lastIndexOf(s3), 0);
}

testLastIndexOf();

function testIndexOf() {
    var s1 = toLatin1("abcdefgh123456d\u00AAefghi");
    var s2 = toLatin1("456d\u00AA");
    assertEq(s1.indexOf(s1), 0);
    assertEq(s1.indexOf(s2), 11);
    assertEq(s1.indexOf(s2, 12), -1);
    assertEq(s2.indexOf(s1), -1);
    assertEq(s1.indexOf("abc\u1234"), -1);
    assertEq(s1.indexOf("def\u1234".substring(0, 3)), 3);
    assertEq(s1.indexOf("d\u00AAef\u1234".substring(0, 3), 9), 14);
    var s3 = "123456d\u00AAefg\u1123a456d\u00AAefg";
    assertEq(isLatin1(s2), true);
    assertEq(s3.indexOf(s2), 3);
    assertEq(s3.indexOf(s2, 11), 13);
    assertEq(s3.indexOf(toLatin1("d\u00AAefg7")), -1);
    assertEq(s3.indexOf("\u1123a4"), 11);
    assertEq(s3.indexOf("\u1123a4", 12), -1);
    assertEq(s3.indexOf("\u1123a\u1098"), -1);
    assertEq(s3.indexOf(s3), 0);
}

testIndexOf();

function testincludes() {
    var s1 = toLatin1("abcdefgh123456defghi\u00EEj");
    var s2 = toLatin1("456defghi\u00EE");
    assertEq(s1.includes(s1), true);
    assertEq(s1.includes(s2), true);
    assertEq(s1.includes(s2, 12), false);
    assertEq(s2.includes(s1), false);
    assertEq(s1.includes("abc\u1234"), false);
    assertEq(s1.includes("def\u1234".substring(0, 3)), true);
    assertEq(s1.includes("def\u1234".substring(0, 3), 9), true);
    var s3 = "123456defg\u1123a456defghi\u00EEj";
    assertEq(isLatin1(s2), true);
    assertEq(s3.includes(s2), true);
    assertEq(s3.includes(s2, 13), false);
    assertEq(s3.includes(toLatin1("defg8")), false);
    assertEq(s3.includes("\u1123a4"), true);
    assertEq(s3.includes("\u1123a4", 11), false);
    assertEq(s3.includes("\u1123a\u1098"), false);
    assertEq(s3.includes(s3), true);
}

testincludes();

function testIndexOfBMH() {
    var s = "012345678901234567890123456789".repeat(20);
    var text = s + "abcdefghijklmnopqrst\u00C1uvwxyz";
    text.indexOf("333");
    var textL1 = toLatin1(text);
    var patL1 = toLatin1("cdefghijklmnopqrst\u00C1uvwx");
    assertEq(textL1.indexOf(patL1), 602);
    assertEq(textL1.indexOf(patL1, 603), -1);
    assertEq(textL1.indexOf(textL1), 0);
    assertEq(textL1.indexOf("cdefghijklmnopqrst\u00C1uvwxy"), 602);
    assertEq(textL1.indexOf("cdefghijklmnopqrst\u00C1uvwxy", 603), -1);
    assertEq(textL1.indexOf("cdefghijklmnopqrst\u00C1uvwxy\uaa00", -1), -1);
    var textTB = s + "abcdefghijklmnopqrst\u00C1uvwxyz\u1200";
    text.indexOf("333");
    assertEq(textTB.indexOf(patL1), 602);
    assertEq(textTB.indexOf(patL1, 603), -1);
    assertEq(textTB.indexOf("defghijklmnopqrst\u00C1uvwxyz\u1200"), 603);
    assertEq(textTB.indexOf("defghijklmnopqrst\u00C1uvwxyz\u1200", 604), -1);
    assertEq(textTB.indexOf("defghijklmnopqrst\u00C1uvwxyz\u1201"), -1);
}

testIndexOfBMH();

function testIndexOfLargePattern() {
    var text = "012345678901234567890123456789".repeat(10) + "abcdefghijklmnopqrst\u00C1uvwxyz";
    text.indexOf("333");
    var pat = "012345678901234567890123456789".repeat(5) + "abcdefghijklmnopqr";
    pat.indexOf("333");
    text = toLatin1(text);
    pat = toLatin1(pat);
    assertEq(text.indexOf(pat), 150);
    assertEq(text.indexOf(pat + "\u1200"), -1);
    assertEq(text.indexOf(pat + "\u1200".slice(0, -1)), 150);
    text = text + "\u1100";
    assertEq(isLatin1(pat), true);
    assertEq(text.indexOf(pat), 150);
    pat = pat + "st\u00C1uvwxyz\u1100";
    assertEq(text.indexOf(pat), 150);
    assertEq(text.indexOf(pat + "\u2000"), -1);
}

testIndexOfLargePattern();
// for-of consults Object.prototype when it encounters a hole.

Object.prototype[1] = 'peek';
var log = [];
for (var x of [0, , 2, 3])
    log.push(x);
assertEq(log[1], 'peek');
assertEq(log.join(), "0,peek,2,3");

vs

Object.prototype[1] = 'peek';

var log = [];

for (x of [0,, 2, 3,]) log.push(x);

assertEq(log[1], 'peek');

assertEq(log.join(), "0,peek,2,3");
// for-of can iterate strict arguments objects.

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;
function test() {
    "use strict";
    for (var v of arguments)
        s += v;
}

s = '';
test();
assertEq(s, '');

s = '';
test('a', 'b');
assertEq(s, 'ab');

vs

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;

function test() {
    'use strict';
    for (v of arguments) s += v;
}

s = '';

test();

assertEq(s, '');

s = '';

test('a', 'b');

assertEq(s, 'ab');
load(libdir + "asserts.js");

function f(tag) { return {[tag](){return 1;}}; }
a = [];
for (var i = 0; i < 2000; i++)
    a[i] = f("first");

for (var i = 0; i < 2000; i++)
    assertEq(a[i].first(), 1);

for (var i = 0; i < 2000; i++)
    a[i] = f("second");

for (var i = 0; i < 2000; i++)
    assertEq(a[i].second(), 1);

vs

load(libdir + "asserts.js");

function f(tag) {
    return {
        [tag]: function() {
            return 1;
        },
    };
}

a = [];

for (let i = 0;i < 2000;i++) a[i] = f("first");

for (let i = 0;i < 2000;i++) assertEq(a[i].first(), 1);

for (let i = 0;i < 2000;i++) a[i] = f("second");

for (let i = 0;i < 2000;i++) assertEq(a[i].second(), 1);
// Two for-of loops on the same slow array get distinct iterators.

var a = [1, 2, 3];
a.slow = true;
var s = '';
for (var x of a)
    s += x;
for (var y of a)
    s += y;
assertEq(s, '123123');

vs

var a = [1, 2, 3,];

a.slow = true;

var s = '';

for (x of a) s += x;

for (y of a) s += y;

assertEq(s, '123123');
// for-of does not skip trailing holes; the value is undefined.

var log = "";
for (var x of [1, 2, 3,,])
    log += x;
assertEq(log, "123undefined");

vs

var log = "";

for (x of [1, 2, 3,,]) log += x;

assertEq(log, "123undefined");
// deoptimize `arguments` in the arrow's closest enclosing non-arrow-function

// non-arrow-function -> arrow function
a = 0;
(function() {
    a = (() => eval("arguments"))();
})(1, 2, 3, 4);
assertEq(a.length, 4);

// non-arrow-function -> arrow function -> arrow function
a = 0;
(function() {
    (() => {
        a = (() => eval("arguments"))();
    })();
})(1, 2, 3, 4);
assertEq(a.length, 4);

// non-arrow-function -> arrow function -> non-arrow-function -> arrow function
a = 0;
(function() {
    (() => {
        (function () {
            a = (() => eval("arguments"))();
        })(1, 2, 3, 4);
    })();
})();
assertEq(a.length, 4);

vs

a = 0;

(function() {
    a = ()  => eval("arguments")();
})(1, 2, 3, 4);

assertEq(a.length, 4);

a = 0;

(function() {
    ()  => {
        a = ()  => eval("arguments")();
    }();
})(1, 2, 3, 4);

assertEq(a.length, 4);

a = 0;

(function() {
    ()  => {
        function() {
            a = ()  => eval("arguments")();
        }(1, 2, 3, 4);
    }();
})();

assertEq(a.length, 4);
// for-of does not skip Array holes. The value at a hole is undefined.

var a = [0, , 2, 3];
var log = [];
for (var x of a) {
    assertEq(x, a[log.length]);
    log.push(x);
}
assertEq(log[1], undefined);
assertEq(log.join(), "0,,2,3");

vs

var a = [0,, 2, 3,];

var log = [];

for (x of a) {
    assertEq(x, a[log.length]);

    log.push(x);
}

assertEq(log[1], undefined);

assertEq(log.join(), "0,,2,3");
// Manually advancing the iterator.

load(libdir + 'iteration.js');

function* g(n) { for (var i=0; i<n; i++) yield i; }

var inner = g(20);

var n = 0;
for (var x of inner) {
    assertEq(x, n * 2);
    assertIteratorNext(inner, n * 2 + 1);
    n++;
}
assertEq(n, 10);

vs

load(libdir + 'iteration.js');

function *g(n) {
    for (let i = 0;i < n;i++) yield i;
}

var inner = g(20);

var n = 0;

for (x of inner) {
    assertEq(x, n * 2);

    assertIteratorNext(inner, n * 2 + 1);

    n++;
}

assertEq(n, 10);
// Parameter default values work in arrow functions

var f = (a=1, b=2, ...rest) => [a, b, rest];
assertEq(f().toSource(), "[1, 2, []]");
assertEq(f(0, 0).toSource(), "[0, 0, []]");
assertEq(f(0, 1, 1, 2, 3, 5).toSource(), "[0, 1, [1, 2, 3, 5]]");

vs

var f = (a = 1, b = 2, rest)  => [a, b, rest,];

assertEq(f().toSource(), "[1, 2, []]");

assertEq(f(0, 0).toSource(), "[0, 0, []]");

assertEq(f(0, 1, 1, 2, 3, 5).toSource(), "[0, 1, [1, 2, 3, 5]]");
// Changing arguments.length affects a for-of loop iterating over arguments.

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;
function f() {
    arguments.length = 2;
    for (var v of arguments)
        s += v;
}

s = '';
f('a', 'b', 'c', 'd', 'e');
assertEq(s, 'ab');

vs

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;

function f() {
    arguments.length = 2;
    for (v of arguments) s += v;
}

s = '';

f('a', 'b', 'c', 'd', 'e');

assertEq(s, 'ab');
// Nested for-of loops can use the same generator-iterator.

function* range(n) {
    for (var i = 0; i < n; i++)
        yield i;
}

var r = range(10);
for (var a of r)
    for (var b of r)
        for (var c of r)
            for (var d of r)
                ;

assertEq(a, 0);
assertEq(b, 1);
assertEq(c, 2);
assertEq(d, 9);

vs

function *range(n) {
    for (let i = 0;i < n;i++) yield i;
}

var r = range(10);

for (a of r) for (b of r) for (c of r) for (d of r) ;

assertEq(a, 0);

assertEq(b, 1);

assertEq(c, 2);

assertEq(d, 9);
g = newGlobal();
g.parent = this;

function installHook() {
    let calledTimes = 0;
    function hook() {
        calledTimes++;

        // Allow the new.target.prototype get to throw.
        if (calledTimes === 1)
            return undefined;

        return {
            return: undefined
        };
    }

    Debugger(parent).onExceptionUnwind = hook;
}


g.eval("(" + installHook + ")()");

var handler = {
    get(t, p) {
        throw new TypeError;
    }
};


var f = new Proxy(function(){}, handler);
new f();

vs

g = newGlobal();

g.parent = this;

function installHook() {
    let calledTimes = 0;
    function hook() {
        calledTimes++;
        if (calledTimes === 1) return undefined;

        return {
            return: undefined,
        };
    }
    Debugger(parent).onExceptionUnwind = hook;
}

g.eval("(" + installHook + ")()");

var handler = ({
    get: (function(t, p) {
        throw new TypeError();
    }),
});

var f = new Proxy((function() { }), handler);

new f();
"use strict";
eval("var x = {}; ({p: function() { x.m; }}).p();");

vs

'use strict';

eval("var x = {}; ({p: function() { x.m; }}).p();");
// for-of works on slow arrays.

var a = ['a', 'b', 'c'];
a.slow = true;
var log = '';
for (var x of a)
    log += x;
assertEq(log, 'abc');

vs

var a = ['a', 'b', 'c',];

a.slow = true;

var log = '';

for (x of a) log += x;

assertEq(log, 'abc');
load(libdir + "iteration.js");

// break in finally.
function *f1() {
    L: try {
        yield 1;
    } finally {
        break L;
    }
    return 2;
}
it = f1();
assertIteratorNext(it, 1);
assertIteratorResult(it.return(4), 2, true);
assertIteratorDone(it);

// continue in finally, followed by return.
function *f2() {
    do try {
        yield 1;
    } catch (e) {
        assertEq(0, 1);
    } finally {
        continue;
    } while (0);
    return 2;
}
it = f2();
assertIteratorNext(it, 1);
assertIteratorResult(it.return(4), 2, true);
assertIteratorDone(it);

// continue in finally, followed by yield.
function *f3() {
    do try {
        yield 1;
    } catch (e) {
        assertEq(0, 1);
    } finally {
        continue;
    } while (0);
    yield 2;
}
it = f3();
assertIteratorNext(it, 1);
assertIteratorResult(it.return(4), 2, false);
assertIteratorDone(it);

// continue in finally.
function *f4() {
    var i = 0;
    while (true) {
        try {
            yield i++;
        } finally {
            if (i < 3)
                continue;
        }
    }
}
it = f4();
assertIteratorNext(it, 0);
assertIteratorResult(it.return(-1), 1, false);
assertIteratorResult(it.return(-2), 2, false);
assertIteratorResult(it.return(-3), -3, true);
assertIteratorDone(it);

vs

load(libdir + "iteration.js");

function *f1() {
    L: try {
        yield 1;
    } finally {
        break L;
    }

    return 2;
}

it = f1();

assertIteratorNext(it, 1);

assertIteratorResult(it.return(4), 2, true);

assertIteratorDone(it);

function *f2() {
    do try {
        yield 1;
    } catch (e) {
        assertEq(0, 1);
    } finally {
        continue;
    }
 while (0);
    ;
    return 2;
}

it = f2();

assertIteratorNext(it, 1);

assertIteratorResult(it.return(4), 2, true);

assertIteratorDone(it);

function *f3() {
    do try {
        yield 1;
    } catch (e) {
        assertEq(0, 1);
    } finally {
        continue;
    }
 while (0);
    ;
    yield 2;
}

it = f3();

assertIteratorNext(it, 1);

assertIteratorResult(it.return(4), 2, false);

assertIteratorDone(it);

function *f4() {
    var i = 0;
    while (true) {
        try {
            yield i++;
        } finally {
            if (i < 3) continue;

        }
    }
}

it = f4();

assertIteratorNext(it, 0);

assertIteratorResult(it.return(-1), 1, false);

assertIteratorResult(it.return(-2), 2, false);

assertIteratorResult(it.return(-3), -3, true);

assertIteratorDone(it);
// Superficial tests of the Array.prototype[@@iterator] builtin function and its workalikes.

load(libdir + "iteration.js");

var constructors = [Array, String, Uint8Array, Uint8ClampedArray];
for (var c of constructors) {
    assertEq(c.prototype[Symbol.iterator].length, 0);

    var loc = (c === Array || c === String)
            ? c.prototype
            : Object.getPrototypeOf(c.prototype);

    var desc = Object.getOwnPropertyDescriptor(loc, Symbol.iterator);
    assertEq(desc.configurable, true);
    assertEq(desc.enumerable, false);
    assertEq(desc.writable, true);
}

vs

load(libdir + "iteration.js");

var constructors = [Array, String, Uint8Array, Uint8ClampedArray,];

for (c of constructors) {
    assertEq(c.prototype[Symbol.iterator].length, 0);

    var loc = c === Array || c === String ? c.prototype : Object.getPrototypeOf(c.prototype);

    var desc = Object.getOwnPropertyDescriptor(loc, Symbol.iterator);

    assertEq(desc.configurable, true);

    assertEq(desc.enumerable, false);

    assertEq(desc.writable, true);
}
load(libdir + "asserts.js");

assertThrowsInstanceOf(function () { readlineBuf() }, Error);

var testBuffers = [
    "foo\nbar\nbaz\n",
    "foo\nbar\nbaz",
    "foo\n\nbar\nbaz",
    "f",
    "\n",
    "\nf",
    "",
    "Ää\n\u{10ffff}",
];

var expected = [
    [ "foo", "bar", "baz" ],
    [ "foo", "bar", "baz" ],
    [ "foo", "", "bar", "baz" ],
    [ "f" ],
    [ "" ],
    [ "", "f" ],
    [],
    ["Ää", "\u{10ffff}"],
];

for (var [idx, testValue] of testBuffers.entries()) {
    readlineBuf(testValue);
    var result = [];

    while ((line = readlineBuf()) != null) {
        result.push(line);
    }

    assertDeepEq(result, expected[idx]);
}

readlineBuf(testBuffers[0]);
readlineBuf();
readlineBuf();
readlineBuf(testBuffers[3]);
assertEq(readlineBuf(), expected[3][0]);

vs

load(libdir + "asserts.js");

assertThrowsInstanceOf((function() {
    readlineBuf();
}), Error);

var testBuffers = ["foo\nbar\nbaz\n", "foo\nbar\nbaz", "foo\n\nbar\nbaz", "f", "\n", "\nf", "", "Ää\n\u{10ffff}",];

var expected = [["foo", "bar", "baz",], ["foo", "bar", "baz",], ["foo", "", "bar", "baz",], ["f",], ["",], ["", "f",], [], ["Ää", "\u{10ffff}",],];

for ([idx,testValue,] of testBuffers.entries()) {
    readlineBuf(testValue);

    var result = [];

    while (line = readlineBuf() != null) {
        result.push(line);
    }

    assertDeepEq(result, expected[idx]);
}

readlineBuf(testBuffers[0]);

readlineBuf();

readlineBuf();

readlineBuf(testBuffers[3]);

assertEq(readlineBuf(), expected[3][0]);
// Tests for the assertEqual function in jit-test/lib/asserts.js

load(libdir + "asserts.js");

function assertNotDeepEq(a, b, options) {
    assertThrowsInstanceOf(() => assertDeepEq(a, b, options), Error);
}

// primitives
assertDeepEq(undefined, undefined);
assertDeepEq("1", "1");
assertNotDeepEq(1, "1");
assertNotDeepEq(undefined, null);
assertNotDeepEq({}, null);

// symbols
assertDeepEq(Symbol(), Symbol());
assertNotDeepEq(Symbol(), Symbol(""));
assertDeepEq(Symbol("tweedledum"), Symbol("tweedledum"));
assertNotDeepEq(Symbol("tweedledum"), Symbol("alice"));
assertNotDeepEq(Symbol("what-its-called"), Symbol.for("what-its-called"));
assertNotDeepEq(Symbol.iterator, Symbol.for("Symbol.iterator"));
assertDeepEq([Symbol(), Symbol(), Symbol()],
             [Symbol(), Symbol(), Symbol()]);
var sym = Symbol();
assertDeepEq([sym, sym], [sym, sym]);
assertNotDeepEq([sym, sym], [Symbol(), Symbol()]);
assertNotDeepEq([sym, sym], [Symbol(), sym]);
var obj1 = {}, obj2 = {};
obj1[Symbol("x")] = "y";
obj2[Symbol("x")] = "y";
assertDeepEq(obj1, obj2);

// objects
assertDeepEq({}, {});
assertDeepEq({one: 1, two: 2}, {one: 1, two: 2});
assertNotDeepEq(Object.freeze({}), {});
assertDeepEq(Object.create(null), Object.create(null));
assertNotDeepEq(Object.create(null, {a: {configurable: false, value: 3}}),
               Object.create(null, {a: {configurable: true, value: 3}}));
assertNotDeepEq({one: 1}, {one: 1, two: 2});
assertNotDeepEq({yes: true}, {oui: true});
assertNotDeepEq({zero: 0}, {zero: "0"});

// test the comment
var x = {}, y = {}, ax = [x];
assertDeepEq([ax, x], [ax, y]);  // passes (bogusly)
assertNotDeepEq([ax, x], [ax, y], {strictEquivalence: true});
assertDeepEq([x, ax], [y, ax]);  // passes (bogusly)
assertNotDeepEq([x, ax], [y, ax], {strictEquivalence: true});

// object identity
assertNotDeepEq([x, y], [x, x]);
assertDeepEq([x, y], [x, y]);
assertDeepEq([y, x], [x, y]);

// proto chain
var x = {};
assertDeepEq(Object.create(x), Object.create(x));
assertDeepEq(Object.create({}), Object.create({})); // equivalent but not identical proto objects

// arrays
assertDeepEq([], []);
assertNotDeepEq([], [1]);
assertDeepEq([1], [1]);
assertNotDeepEq([0], [1]);
assertDeepEq([1, 2, 3], [1, 2, 3]);
assertNotDeepEq([1, , 3], [1, undefined, 3]);
var p = [], q = [];
p.prop = 1;
assertNotDeepEq(p, q);
assertNotDeepEq(q, p);
q.prop = 1;
assertDeepEq(q, p);

// functions
assertNotDeepEq(() => 1, () => 2);
assertNotDeepEq((...x) => 1, x => 1);
assertNotDeepEq(function f(){}, function g(){});
// Avoid setting name property.
var [f1, f2] = [function () {}, function () {}];
assertDeepEq(f1, f1);
assertDeepEq(f1, f2);  // same text, close enough
f1.prop = 1;
assertNotDeepEq(f1, f2);
f2.prop = 1;
assertDeepEq(f1, f2);

// recursion
var a = [], b = [];
a[0] = a;
b[0] = b;
assertDeepEq(a, b);
a[0] = b;
assertNotDeepEq(a, b);  // [#1=[#1#]] is not structurally equivalent to #1=[[#1#]]
b[0] = a;
assertDeepEq(a, b);
b[0] = [a];  // a[0] === b, b[0] === c, c[0] === a
assertDeepEq(a, b);

// objects that merge
var x = {};
assertDeepEq({x: x}, {x: x});
var y = [x];
assertDeepEq([y], [y]);

// cross-compartment
var g1 = newGlobal(), g2 = newGlobal();
assertDeepEq(g1, g2);
assertDeepEq(g1, g2, {strictEquivalence: true});
Object.preventExtensions(g2.Math.abs);  // make some miniscule change
assertNotDeepEq(g1, g2);

vs

load(libdir + "asserts.js");

function assertNotDeepEq(a, b, options) {
    assertThrowsInstanceOf(()  => assertDeepEq(a, b, options), Error);
}

assertDeepEq(undefined, undefined);

assertDeepEq("1", "1");

assertNotDeepEq(1, "1");

assertNotDeepEq(undefined, null);

assertNotDeepEq(({}), null);

assertDeepEq(Symbol(), Symbol());

assertNotDeepEq(Symbol(), Symbol(""));

assertDeepEq(Symbol("tweedledum"), Symbol("tweedledum"));

assertNotDeepEq(Symbol("tweedledum"), Symbol("alice"));

assertNotDeepEq(Symbol("what-its-called"), Symbol.for("what-its-called"));

assertNotDeepEq(Symbol.iterator, Symbol.for("Symbol.iterator"));

assertDeepEq([Symbol(), Symbol(), Symbol(),], [Symbol(), Symbol(), Symbol(),]);

var sym = Symbol();

assertDeepEq([sym, sym,], [sym, sym,]);

assertNotDeepEq([sym, sym,], [Symbol(), Symbol(),]);

assertNotDeepEq([sym, sym,], [Symbol(), sym,]);

var obj1 = ({}), obj2 = ({});

obj1[Symbol("x")] = "y";

obj2[Symbol("x")] = "y";

assertDeepEq(obj1, obj2);

assertDeepEq(({}), ({}));

assertDeepEq(({
    one: 1,
    two: 2,
}), ({
    one: 1,
    two: 2,
}));

assertNotDeepEq(Object.freeze(({})), ({}));

assertDeepEq(Object.create(null), Object.create(null));

assertNotDeepEq(Object.create(null, ({
    a: ({
        configurable: false,
        value: 3,
    }),
})), Object.create(null, ({
    a: ({
        configurable: true,
        value: 3,
    }),
})));

assertNotDeepEq(({
    one: 1,
}), ({
    one: 1,
    two: 2,
}));

assertNotDeepEq(({
    yes: true,
}), ({
    oui: true,
}));

assertNotDeepEq(({
    zero: 0,
}), ({
    zero: "0",
}));

var x = ({}), y = ({}), ax = [x,];

assertDeepEq([ax, x,], [ax, y,]);

assertNotDeepEq([ax, x,], [ax, y,], ({
    strictEquivalence: true,
}));

assertDeepEq([x, ax,], [y, ax,]);

assertNotDeepEq([x, ax,], [y, ax,], ({
    strictEquivalence: true,
}));

assertNotDeepEq([x, y,], [x, x,]);

assertDeepEq([x, y,], [x, y,]);

assertDeepEq([y, x,], [x, y,]);

var x = ({});

assertDeepEq(Object.create(x), Object.create(x));

assertDeepEq(Object.create(({})), Object.create(({})));

assertDeepEq([], []);

assertNotDeepEq([], [1,]);

assertDeepEq([1,], [1,]);

assertNotDeepEq([0,], [1,]);

assertDeepEq([1, 2, 3,], [1, 2, 3,]);

assertNotDeepEq([1,, 3,], [1, undefined, 3,]);

var p = [], q = [];

p.prop = 1;

assertNotDeepEq(p, q);

assertNotDeepEq(q, p);

q.prop = 1;

assertDeepEq(q, p);

assertNotDeepEq(()  => 1, ()  => 2);

assertNotDeepEq(x => 1, x => 1);

assertNotDeepEq((function f() { }), (function g() { }));

var [f1,f2,] = [(function() { }), (function() { }),];

assertDeepEq(f1, f1);

assertDeepEq(f1, f2);

f1.prop = 1;

assertNotDeepEq(f1, f2);

f2.prop = 1;

assertDeepEq(f1, f2);

var a = [], b = [];

a[0] = a;

b[0] = b;

assertDeepEq(a, b);

a[0] = b;

assertNotDeepEq(a, b);

b[0] = a;

assertDeepEq(a, b);

b[0] = [a,];

assertDeepEq(a, b);

var x = ({});

assertDeepEq(({
    x: x,
}), ({
    x: x,
}));

var y = [x,];

assertDeepEq([y,], [y,]);

var g1 = newGlobal(), g2 = newGlobal();

assertDeepEq(g1, g2);

assertDeepEq(g1, g2, ({
    strictEquivalence: true,
}));

Object.preventExtensions(g2.Math.abs);

assertNotDeepEq(g1, g2);
// For-of passes one arg to "next".

load(libdir + 'iteration.js')

var log = '';

function Iter() {
    function next() {
        log += 'n';
        assertEq(arguments.length, 0)
        assertEq(arguments[0], undefined)
        return { get value() { throw 42; }, done: true }
    }

    this[Symbol.iterator] = function () { return this; }
    this.next = next;
}

for (var x of new Iter())
    throw 'not reached';

assertEq(log, 'n');

vs

load(libdir + 'iteration.js');

var log = '';

function Iter() {
    function next() {
        log += 'n';
        assertEq(arguments.length, 0);
        assertEq(arguments[0], undefined);
        return {
            get value() {
                throw 42;
            },
            done: true,
        };
    }
    this[Symbol.iterator] = function() {
        return this;
    };
    this.next = next;
}

for (x of new Iter()) throw 'not reached';

assertEq(log, 'n');
// Arrow functions can have primitive |this| values.

Number.prototype.foo = function() {
    "use strict";
    return () => this;
}

for (var i=0; i<5; i++) {
    var n = i.foo()();
    assertEq(typeof n, "number");
    assertEq(n, i);
}

vs

Number.prototype.foo = (function() {
    'use strict';
    return ()  => this;
});

for (let i = 0;i < 5;i++) {
    var n = i.foo()();

    assertEq(typeof n, "number");

    assertEq(n, i);
}
function test() {
    var arr = new Int8Array(400);
    var idx = "384";

    arr[idx] = 9;
    assertEq(arr[idx], 9);
    arr[idx] = 10;
    assertEq(arr[384], 10);

    idx = "512";
    assertEq(arr[idx], undefined);
    assertEq(arr[(() => "byteLength")()], 400);

    var o = {};
    Object.defineProperty(o, idx, {value: 123});
    assertEq(o[512], 123);

    var propLatin1 = "foobar";
    o[propLatin1] = 3;
    assertEq(o.foobar, 3);

    var propTwoByte = "foobar\u1200";
    o[propTwoByte] = 4;
    assertEq(o.foobar\u1200, 4);
}
test();

vs

function test() {
    var arr = new Int8Array(400);
    var idx = "384";
    arr[idx] = 9;
    assertEq(arr[idx], 9);
    arr[idx] = 10;
    assertEq(arr[384], 10);
    idx = "512";
    assertEq(arr[idx], undefined);
    assertEq(arr[()  => "byteLength"()], 400);
    var o = {    };
    Object.defineProperty(o, idx, {
        value: 123,
    });
    assertEq(o[512], 123);
    var propLatin1 = "foobar";
    o[propLatin1] = 3;
    assertEq(o.foobar, 3);
    var propTwoByte = "foobar\u1200";
    o[propTwoByte] = 4;
    assertEq(o.foobar\u1200, 4);
}

test();
// => binds tighter than ,

var f, g;
g = (f, h => h + 1);  // sequence expression: (f, (h => h + 1))
assertEq(g.length, 1);
assertEq(g(37), 38);

vs

var f, g;

g = f, h => h + 1;

assertEq(g.length, 1);

assertEq(g(37), 38);
// for-of on a slow Array consults the prototype chain when it encounters a hole.

var a = [0, , , 3];
a.slow = true;
Object.prototype[1] = 'peek1';
Array.prototype[2] = 'peek2';

var log = [];
for (var x of a)
    log.push(x);
assertEq(log[1], 'peek1');
assertEq(log[2], 'peek2');
assertEq(log.join(), "0,peek1,peek2,3");

vs

var a = [0,,, 3,];

a.slow = true;

Object.prototype[1] = 'peek1';

Array.prototype[2] = 'peek2';

var log = [];

for (x of a) log.push(x);

assertEq(log[1], 'peek1');

assertEq(log[2], 'peek2');

assertEq(log.join(), "0,peek1,peek2,3");
// Assigning to a proxy with no set handler calls the defineProperty handler
// when an existing inherited data property already exists.

var hits = 0;
var proto = {x: 1};
var t = Object.create(proto);
var p = new Proxy(t, {
    defineProperty(t, id, desc) { hits++; return true; }
});
p.x = 2;
assertEq(hits, 1);
assertEq(proto.x, 1);
assertEq(t.hasOwnProperty("x"), false);

// Same thing, but the receiver is a plain object inheriting from p:
var receiver = Object.create(p);
receiver.x = 2;
assertEq(hits, 1);
assertEq(t.hasOwnProperty("x"), false);
assertEq(receiver.hasOwnProperty("x"), true);
assertEq(receiver.x, 2);

vs

var hits = 0;

var proto = ({
    x: 1,
});

var t = Object.create(proto);

var p = new Proxy(t, ({
    defineProperty: (function(t, id, desc) {
        hits++;
        return true;
    }),
}));

p.x = 2;

assertEq(hits, 1);

assertEq(proto.x, 1);

assertEq(t.hasOwnProperty("x"), false);

var receiver = Object.create(p);

receiver.x = 2;

assertEq(hits, 1);

assertEq(t.hasOwnProperty("x"), false);

assertEq(receiver.hasOwnProperty("x"), true);

assertEq(receiver.x, 2);
// A for-of loop over an array stops at the new end of the array if it shrinks during iteration.

function ispal(arr) {
    for (var v of arr) {
        if (v !== arr.pop())
            return false;
    }
    return true;
}

assertEq(ispal([1, 2, 3, 4, 3, 2, 1]), true);
assertEq(ispal([1, 2, 3, 3, 2, 1]), true);
assertEq(ispal([1, 2, 3, 4, 2, 1]), false);

vs

function ispal(arr) {
    for (v of arr) {
        if (v !== arr.pop()) return false;

    }
    return true;
}

assertEq(ispal([1, 2, 3, 4, 3, 2, 1,]), true);

assertEq(ispal([1, 2, 3, 3, 2, 1,]), true);

assertEq(ispal([1, 2, 3, 4, 2, 1,]), false);
// String.prototype[@@iterator] and StringIterator.prototype surface tests

load(libdir + "array-compare.js");
load(libdir + "asserts.js");
load(libdir + "iteration.js");

function assertDataDescriptor(actual, expected) {
    assertEq(actual.value, expected.value);
    assertEq(actual.writable, expected.writable);
    assertEq(actual.enumerable, expected.enumerable);
    assertEq(actual.configurable, expected.configurable);
}

function isConstructor(o) {
    try {
        new (new Proxy(o, {construct: () => ({})}));
        return true;
    } catch(e) {
        return false;
    }
}

function assertBuiltinFunction(o, name, arity) {
    var fn = o[name];
    assertDataDescriptor(Object.getOwnPropertyDescriptor(o, name), {
        value: fn,
        writable: true,
        enumerable: false,
        configurable: true,
    });

    assertEq(typeof fn, "function");
    assertEq(Object.getPrototypeOf(fn), Function.prototype);
    assertEq(isConstructor(fn), false);

    assertEq(arraysEqual(Object.getOwnPropertyNames(fn).sort(), ["length", "name"].sort()), true);

    assertDataDescriptor(Object.getOwnPropertyDescriptor(fn, "length"), {
        value: arity,
        writable: false,
        enumerable: false,
        configurable: true
    });

    var functionName = typeof name === "symbol"
                       ? String(name).replace(/^Symbol\((.+)\)$/, "[$1]")
                       : name;
    assertDataDescriptor(Object.getOwnPropertyDescriptor(fn, "name"), {
        value: functionName,
        writable: false,
        enumerable: false,
        configurable: true
    });
}


// String.prototype[@@iterator] is a built-in function
assertBuiltinFunction(String.prototype, Symbol.iterator, 0);

// Test StringIterator.prototype surface
var iter = ""[Symbol.iterator]();
var iterProto = Object.getPrototypeOf(iter);

// StringIterator.prototype inherits from %IteratorPrototype%. Check it's the
// same object as %ArrayIteratorPrototype%'s proto.
assertEq(Object.getPrototypeOf(iterProto),
         Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));

// Own properties for StringIterator.prototype: "next"
assertEq(arraysEqual(Object.getOwnPropertyNames(iterProto).sort(), ["next"]), true);

// StringIterator.prototype.next is a built-in function
assertBuiltinFunction(iterProto, "next", 0);

// StringIterator.prototype[@@iterator] is generic and returns |this|
for (var v of [void 0, null, true, false, "", 0, 1, {}, [], iter, iterProto]) {
    assertEq(iterProto[Symbol.iterator].call(v), v);
}

// StringIterator.prototype.next is not generic
for (var v of [void 0, null, true, false, "", 0, 1, {}, [], iterProto]) {
    assertThrowsInstanceOf(() => iterProto.next.call(v), TypeError);
}

vs

load(libdir + "array-compare.js");

load(libdir + "asserts.js");

load(libdir + "iteration.js");

function assertDataDescriptor(actual, expected) {
    assertEq(actual.value, expected.value);
    assertEq(actual.writable, expected.writable);
    assertEq(actual.enumerable, expected.enumerable);
    assertEq(actual.configurable, expected.configurable);
}

function isConstructor(o) {
    try {
        new new Proxy(o, {
            construct: ()  => ({            }),
        })();

        return true;
    } catch (e) {
        return false;
    }
}

function assertBuiltinFunction(o, name, arity) {
    var fn = o[name];
    assertDataDescriptor(Object.getOwnPropertyDescriptor(o, name), {
        value: fn,
        writable: true,
        enumerable: false,
        configurable: true,
    });
    assertEq(typeof fn, "function");
    assertEq(Object.getPrototypeOf(fn), Function.prototype);
    assertEq(isConstructor(fn), false);
    assertEq(arraysEqual(Object.getOwnPropertyNames(fn).sort(), ["length", "name",].sort()), true);
    assertDataDescriptor(Object.getOwnPropertyDescriptor(fn, "length"), {
        value: arity,
        writable: false,
        enumerable: false,
        configurable: true,
    });
    var functionName = typeof name === "symbol" ? String(name).replace(/^Symbol\((.+)\)$/, "[$1]") : name;
    assertDataDescriptor(Object.getOwnPropertyDescriptor(fn, "name"), {
        value: functionName,
        writable: false,
        enumerable: false,
        configurable: true,
    });
}

assertBuiltinFunction(String.prototype, Symbol.iterator, 0);

var iter = ""[Symbol.iterator]();

var iterProto = Object.getPrototypeOf(iter);

assertEq(Object.getPrototypeOf(iterProto), Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));

assertEq(arraysEqual(Object.getOwnPropertyNames(iterProto).sort(), ["next",]), true);

assertBuiltinFunction(iterProto, "next", 0);

for (v of [void 0, null, true, false, "", 0, 1, {}, [], iter, iterProto,]) {
    assertEq(iterProto[Symbol.iterator].call(v), v);
}

for (v of [void 0, null, true, false, "", 0, 1, {}, [], iterProto,]) {
    assertThrowsInstanceOf(()  => iterProto.next.call(v), TypeError);
}
// A for-of loop over an array continues to the end if the array grows during iteration.

var a = [0, 1, 1, 0, 1, 0, 0];
var s = '';
for (var v of a) {
    s += v;
    if (v === 1)
        a.push(2);
}
assertEq(s, '0110100222');

vs

var a = [0, 1, 1, 0, 1, 0, 0,];

var s = '';

for (v of a) {
    s += v;

    if (v === 1) a.push(2);

}

assertEq(s, '0110100222');
// Changing arguments.length during a for-of loop iterating over arguments affects the loop.

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;
function f() {
    for (var v of arguments) {
        s += v;
        arguments.length--;
    }
}

s = '';
f('a', 'b', 'c', 'd', 'e');
assertEq(s, 'abc');

vs

load(libdir + "iteration.js");

Object.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

var s;

function f() {
    for (v of arguments) {
        s += v;

        arguments.length--;
    }
}

s = '';

f('a', 'b', 'c', 'd', 'e');

assertEq(s, 'abc');
// Destructuring does not occur when the target of for-of is an empty typed array.

for (var [[x]] of new Int32Array(0))
    throw "FAIL";

vs

for ([[x,],] of new Int32Array(0)) throw "FAIL";
// Return the trap result
function setFoo(x,y) { this.foo = x + y; }
var handler = { construct: function (target, args) { return { foo : args[0] * args[1]}; } }

for (let proxy of [new Proxy(setFoo, handler), Proxy.revocable(setFoo, handler).proxy]) {
    var obj1 = new proxy(2, 3);
    assertEq(obj1.foo, 6);
    obj1.bar = proxy;
    var obj2 = new obj1.bar(2, 3);
    assertEq(obj2.foo, 6);
}

vs

function setFoo(x, y) {
    this.foo = x + y;
}

var handler = ({
    construct: (function(target, args) {
        return {
            foo: args[0] * args[1],
        };
    }),
});

for (proxy of [new Proxy(setFoo, handler), Proxy.revocable(setFoo, handler).proxy,]) {
    var obj1 = new proxy(2, 3);

    assertEq(obj1.foo, 6);

    obj1.bar = proxy;

    var obj2 = new obj1.bar(2, 3);

    assertEq(obj2.foo, 6);
}
// for-of can iterate over float typed arrays containing infinities or NaNs.

var values = [Infinity, -Infinity, -0, NaN];
for (var C of [Float32Array, Float64Array]) {
    var i = 0;
    for (var v of new C(values))
        assertEq(v, values[i++]);
    assertEq(i, values.length);
}

vs

var values = [Infinity, -Infinity, -0, NaN,];

for (C of [Float32Array, Float64Array,]) {
    var i = 0;

    for (v of new C(values)) assertEq(v, values[i++]);

    assertEq(i, values.length);
}
// for-of throws if the target is an ArrayBuffer.

load(libdir + "asserts.js");
assertThrowsInstanceOf(function () {
    for (var v of new Int8Array([0, 1, 2, 3]).buffer)
        throw "FAIL";
}, TypeError);

vs

load(libdir + "asserts.js");

assertThrowsInstanceOf((function() {
    for (v of new Int8Array([0, 1, 2, 3,]).buffer) throw "FAIL";
}), TypeError);
// |jit-test| error: ReferenceError
for (let a in [0])
a = e
for (let a in [0])
(function () {
    a
})

vs

for (a in [0,]) a = e;

for (a in [0,]) function() {
    a;
};
// for-of can iterate over typed arrays.

var a = new Int8Array([0, 1, -7, 3])
var s = '';
for (var v of a)
    s += v + ',';
assertEq(s, '0,1,-7,3,');

vs

var a = new Int8Array([0, 1, -7, 3,]);

var s = '';

for (v of a) s += v + ',';

assertEq(s, '0,1,-7,3,');
// Basic for-of test with Proxy.

var s = '';
var arr = ['a', 'b', 'c', 'd'];
var p = new Proxy(arr, {});

// Test the same proxy twice.
for (var i = 0; i < 2; i++) {
    var j = 0;
    for (var x of p)
        assertEq(x, arr[j++]);
    assertEq(j, arr.length);
}

vs

var s = '';

var arr = ['a', 'b', 'c', 'd',];

var p = new Proxy(arr, ({}));

for (let i = 0;i < 2;i++) {
    var j = 0;

    for (x of p) assertEq(x, arr[j++]);

    assertEq(j, arr.length);
}
// Generator-iterators are consumed the first time they are iterated.

function* range(n) {
    for (var i = 0; i < n; i++)
        yield i;
}

var r = range(10);
var i = 0;
for (var x of r)
    assertEq(x, i++);
assertEq(i, 10);
for (var y of r)
    throw "FAIL";
assertEq(y, undefined);

vs

function *range(n) {
    for (let i = 0;i < n;i++) yield i;
}

var r = range(10);

var i = 0;

for (x of r) assertEq(x, i++);

assertEq(i, 10);

for (y of r) throw "FAIL";

assertEq(y, undefined);
// |jit-test| error: TypeError

var g = newGlobal();
g.parent = this;
g.eval("(" + function() {
    var dbg = new Debugger(parent);
    dbg.onExceptionUnwind = function(frame) {
        frame.older.onStep = function() {}
    };
} + ")()");
function f() {
    (function inner(arr) {
        inner(arr.map);
    })([]);
}
f();

vs

var g = newGlobal();

g.parent = this;

g.eval("(" + (function() {
    var dbg = new Debugger(parent);
    dbg.onExceptionUnwind = function(frame) {
        frame.older.onStep = function() { };
    };
}) + ")()");

function f() {
    function inner(arr) {
        inner(arr.map);
    }([]);
}

f();
// Tests that NX disallows debuggee execution for all debuggees.

load(libdir + "asserts.js");
load(libdir + "debuggerNXHelper.js");

var g1 = newGlobal();
var g2 = newGlobal();
var dbg = new Debugger;

dbg.addDebuggee(g1);
dbg.addDebuggee(g2);

g1.eval(`
        function f() { }
        var o = {
          get p() { },
          set p(x) { }
        };
        `);

g2.eval(`
        function f() { }
        var o = {
          get p() { },
          set p(x) { }
        };
        `);

var handlers = [() => { g1.f(); },
                () => { g1.o.p } ,
                () => { g1.o.p = 42; },
                () => { g2.f(); },
                () => { g2.o.p } ,
                () => { g2.o.p = 42; } ];

function testHook(hookName) {
  for (var h of handlers) {
    assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
  }
}

testDebuggerHooksNX(dbg, g1, testHook);
testDebuggerHooksNX(dbg, g2, testHook);

vs

load(libdir + "asserts.js");

load(libdir + "debuggerNXHelper.js");

var g1 = newGlobal();

var g2 = newGlobal();

var dbg = new Debugger();

dbg.addDebuggee(g1);

dbg.addDebuggee(g2);

g1.eval(`
        function f() { }
        var o = {
          get p() { },
          set p(x) { }
        };
        `);

g2.eval(`
        function f() { }
        var o = {
          get p() { },
          set p(x) { }
        };
        `);

var handlers = [()  => {
    g1.f();
}, ()  => {
    g1.o.p;
}, ()  => {
    g1.o.p = 42;
}, ()  => {
    g2.f();
}, ()  => {
    g2.o.p;
}, ()  => {
    g2.o.p = 42;
},];

function testHook(hookName) {
    for (h of handlers) {
        assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
    }
}

testDebuggerHooksNX(dbg, g1, testHook);

testDebuggerHooksNX(dbg, g2, testHook);
/*
 * Call the trap with the handler as the this value, and the target as the first
 * argument
 */
var target = {};
var called = false;
var handler = {
    ownKeys: function (target1) {
        assertEq(this, handler);
        assertEq(target1, target);
        called = true;
        return [];
    }
};

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    assertEq(Object.getOwnPropertyNames(p).length, 0);
    assertEq(called, true);
}

vs

var target = ({});

var called = false;

var handler = ({
    ownKeys: (function(target1) {
        assertEq(this, handler);
        assertEq(target1, target);
        called = true;
        return [];
    }),
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    assertEq(Object.getOwnPropertyNames(p).length, 0);

    assertEq(called, true);
}
// Two for-of loops on the same array get distinct iterators.

var a = [1, 2, 3];
var s = '';
for (var x of a)
    s += x;
for (var y of a)
    s += y;
assertEq(s, '123123');

vs

var a = [1, 2, 3,];

var s = '';

for (x of a) s += x;

for (y of a) s += y;

assertEq(s, '123123');
// Arguments with default parameters can shadow const locals.

"use strict";

function f() {
    const x = 1;
    return (x = 0) => x;
}

var g = f();
assertEq(g(), 0);

vs

'use strict';

function f() {
    const x = 1;
    return x = 0 => x;
}

var g = f();

assertEq(g(), 0);
// Return the trap result
// Man, wouldn't haskell's "uninfix" be cleaner? (+)
function justAdd(x, y) {
    return x + y;
}

var handler = { apply : function (target, receiver, args) { return args[0] * args[1]; } };

for (let p of [new Proxy(justAdd, handler), Proxy.revocable(justAdd, handler).proxy])
    assertEq(p(2,3), 6);

vs

function justAdd(x, y) {
    return x + y;
}

var handler = ({
    apply: (function(target, receiver, args) {
        return args[0] * args[1];
    }),
});

for (p of [new Proxy(justAdd, handler), Proxy.revocable(justAdd, handler).proxy,]) assertEq(p(2, 3), 6);
// for-of on an empty slow array does nothing.

var a = [];
a.slow = true;
for (var x of a)
    fail();

vs

var a = [];

a.slow = true;

for (x of a) fail();
// Inserting values in an array does not change the next index of an existing iterator.

var a = [1, 2, 3, 4];
var s = '';
for (var v of a) {
    s += v;
    if (s.length === 2)
        a.unshift('x');
}
assertEq(s, '12234');

vs

var a = [1, 2, 3, 4,];

var s = '';

for (v of a) {
    s += v;

    if (s.length === 2) a.unshift('x');

}

assertEq(s, '12234');
// Deleting the .next method makes for-of stop working on arrays.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

var iterProto = Object.getPrototypeOf([][Symbol.iterator]());
delete iterProto.next;
assertThrowsInstanceOf(function () { for (var v of []) ; }, TypeError);

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

var iterProto = Object.getPrototypeOf([][Symbol.iterator]());

delete iterProto.next;

assertThrowsInstanceOf((function() {
    for (v of []) ;
}), TypeError);
load(libdir + "asserts.js");

// Throw a TypeError if the trap does not return an object

var handler = { ownKeys: () => undefined };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.keys(p), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    ownKeys: ()  => undefined,
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.keys(p), TypeError);
// Rest parameters work in arrow functions

var f = (a, b, ...rest) => [a, b, rest];
assertEq(f().toSource(), "[(void 0), (void 0), []]");
assertEq(f(1, 2, 3, 4).toSource(), "[1, 2, [3, 4]]");

vs

var f = (a, b, rest)  => [a, b, rest,];

assertEq(f().toSource(), "[(void 0), (void 0), []]");

assertEq(f(1, 2, 3, 4).toSource(), "[1, 2, [3, 4]]");
// for-of is defined in terms of basic operations on objects, particularly
// [[Get]] for properties named "iterator" and "next", and [[Call]]. These
// "semantics" tests check that for-of really does appear to be implemented in
// terms of those more basic operations, as required by the spec, even in
// unusual cases.

// Deleting Array.prototype.iterator makes for-of stop working on arrays.

load(libdir + "asserts.js");
load(libdir + "iteration.js");

delete Array.prototype[Symbol.iterator];
assertThrowsInstanceOf(function () { for (var x of []) ; }, TypeError);

vs

load(libdir + "asserts.js");

load(libdir + "iteration.js");

delete Array.prototype[Symbol.iterator];

assertThrowsInstanceOf((function() {
    for (x of []) ;
}), TypeError);
// |jit-test| skip-if: helperThreadCount() === 0

function evalWithCacheLoadOffThread(code, ctx) {
  ctx = ctx || {};
  ctx = Object.create(ctx, {
    fileName: { value: "evalWithCacheCode.js" },
    lineNumber: { value: 0 }
  });
  code = code instanceof Object ? code : cacheEntry(code);

  var incremental = ctx.incremental || false;

  // We create a new global ...
  if (!("global" in ctx))
    ctx.global = newGlobal({ cloneSingletons: !incremental });

  var ctx_save;
  if (incremental)
    ctx_save = Object.create(ctx, {saveIncrementalBytecode: { value: true } });
  else
    ctx_save = Object.create(ctx, {saveBytecode: { value: true } });

  ctx.global.generation = 0;
  evaluate(code, ctx_save);

  offThreadDecodeScript(code, ctx);
  ctx.global.eval(`runOffThreadDecodedScript()`);
}

var test;

// Decode a constant.
test = `
  1;
`;
evalWithCacheLoadOffThread(test, {});
evalWithCacheLoadOffThread(test, { incremental: true });

// Decode object literals.
test = `
  var obj = { a: 1, b: 2 };
  obj.a++;
  assertEq(obj.a, 2);
`;
evalWithCacheLoadOffThread(test, {});
evalWithCacheLoadOffThread(test, { incremental: true });

// Decode functions.
test = `
  function g() {
    return function f() { return 1; };
  };
  assertEq(g()(), 1);
`;
evalWithCacheLoadOffThread(test, {});
evalWithCacheLoadOffThread(test, { incremental: true });

vs

function evalWithCacheLoadOffThread(code, ctx) {
    ctx = ctx || {    };
    ctx = Object.create(ctx, {
        fileName: {
            value: "evalWithCacheCode.js",
        },
        lineNumber: {
            value: 0,
        },
    });
    code = code instanceof Object ? code : cacheEntry(code);
    var incremental = ctx.incremental || false;
    if (!"global" in ctx) ctx.global = newGlobal({
        cloneSingletons: !incremental,
    });

    var ctx_save;
    if (incremental) ctx_save = Object.create(ctx, {
        saveIncrementalBytecode: {
            value: true,
        },
    });
 else ctx_save = Object.create(ctx, {
        saveBytecode: {
            value: true,
        },
    });

    ctx.global.generation = 0;
    evaluate(code, ctx_save);
    offThreadDecodeScript(code, ctx);
    ctx.global.eval(`runOffThreadDecodedScript()`);
}

var test;

test = `
  1;
`;

evalWithCacheLoadOffThread(test, ({}));

evalWithCacheLoadOffThread(test, ({
    incremental: true,
}));

test = `
  var obj = { a: 1, b: 2 };
  obj.a++;
  assertEq(obj.a, 2);
`;

evalWithCacheLoadOffThread(test, ({}));

evalWithCacheLoadOffThread(test, ({
    incremental: true,
}));

test = `
  function g() {
    return function f() { return 1; };
  };
  assertEq(g()(), 1);
`;

evalWithCacheLoadOffThread(test, ({}));

evalWithCacheLoadOffThread(test, ({
    incremental: true,
}));
// Assigning to an existing array element via a proxy with no set handler
// calls the defineProperty handler.

function test(arr) {
    var p = new Proxy(arr, {
        defineProperty(t, id, desc) {
            hits++;

            // ES6 draft rev 28 (2014 Oct 14) 9.1.9 step 5.e.i.
            // Since the property already exists, the system only changes
            // the value. desc is otherwise empty.
            assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
            assertEq(desc.value, "ponies");
            return true;
        }
    });
    var hits = 0;
    p[0] = "ponies";
    assertEq(hits, 1);
    assertEq(arr[0], 123);
}

test([123]);
test(new Int32Array([123]));

vs

function test(arr) {
    var p = new Proxy(arr, {
        defineProperty: function(t, id, desc) {
            hits++;
            assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
            assertEq(desc.value, "ponies");
            return true;
        },
    });
    var hits = 0;
    p[0] = "ponies";
    assertEq(hits, 1);
    assertEq(arr[0], 123);
}

test([123,]);

test(new Int32Array([123,]));
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap reports a new own property on a non-extensible
 * object
 */
var target = {};
Object.preventExtensions(target);

var handler = { ownKeys: () => [ 'foo' ] };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.preventExtensions(target);

var handler = ({
    ownKeys: ()  => ['foo',],
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyNames(p), TypeError);
// Test how stepping interacts with for-in/of statements.

var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
var log;
var previous;

dbg.onDebuggerStatement = function (frame) {
  let debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
  log = '';
  previous = '';
  frame.onStep = function() {
    let foundLine = this.script.getOffsetLocation(this.offset).lineNumber;
    if (this.script.getLineOffsets(foundLine).indexOf(this.offset) >= 0) {
      let thisline = (foundLine - debugLine).toString(16);
      if (thisline !== previous) {
        log += thisline;
        previous = thisline;
      }
    }
  };
};

function testOne(decl, loopKind) {
  let body = "var array = [2, 4, 6];\ndebugger;\nfor (" + decl + " iter " +
      loopKind + " array) {\n  print(iter);\n}\n";
  g.eval(body);
  assertEq(log, "12121214");
}

for (let decl of ["", "var", "let"]) {
  testOne(decl, "in");
  testOne(decl, "of");
}

vs

var g = newGlobal();

var dbg = new Debugger();

var gw = dbg.addDebuggee(g);

var log;

var previous;

dbg.onDebuggerStatement = (function(frame) {
    let debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
    log = '';
    previous = '';
    frame.onStep = function() {
        let foundLine = this.script.getOffsetLocation(this.offset).lineNumber;
        if (this.script.getLineOffsets(foundLine).indexOf(this.offset) >= 0) {
            let thisline = foundLine - debugLine.toString(16);

            if (thisline !== previous) {
                log += thisline;

                previous = thisline;
            }
        }
    };
});

function testOne(decl, loopKind) {
    let body = "var array = [2, 4, 6];\ndebugger;\nfor (" + decl + " iter " + loopKind + " array) {\n  print(iter);\n}\n";
    g.eval(body);
    assertEq(log, "12121214");
}

for (decl of ["", "var", "let",]) {
    testOne(decl, "in");

    testOne(decl, "of");
}
load(libdir + "asserts.js");

// Throw a TypeError if the object refuses to be made non-extensible
var handler = { preventExtensions: () => false };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.preventExtensions(p), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    preventExtensions: ()  => false,
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.preventExtensions(p), TypeError);
// When resuming a generator triggers one Debugger's onEnterFrame handler,
// all Debuggers' Debugger.Frames become usable at once.

let g = newGlobal();
g.eval(`
    function* f() {
       yield 1;
    }
`);
let dbg1 = new Debugger(g);
let dbg2 = new Debugger(g);

let hits = 0;
let savedFrame1;
let savedFrame2;
dbg1.onEnterFrame = frame => {
    if (savedFrame1 === undefined) {
        savedFrame1 = frame;
        savedFrame2 = dbg2.getNewestFrame();
    } else {
        hits++;
        assertEq(savedFrame1, frame);
        for (let f of [savedFrame2, savedFrame1]) {
            assertEq(f.type, "call");
            assertEq(f.callee.name, "f");
        }
    }
};

let values = [...g.f()];
assertEq(hits, 2);
assertEq(values.toSource(), "[1]");

vs

let g = newGlobal();

g.eval(`
    function* f() {
       yield 1;
    }
`);

let dbg1 = new Debugger(g);

let dbg2 = new Debugger(g);

let hits = 0;

let savedFrame1;

let savedFrame2;

dbg1.onEnterFrame = frame => {
    if (savedFrame1 === undefined) {
        savedFrame1 = frame;

        savedFrame2 = dbg2.getNewestFrame();
    } else {
        hits++;

        assertEq(savedFrame1, frame);

        for (f of [savedFrame2, savedFrame1,]) {
            assertEq(f.type, "call");

            assertEq(f.callee.name, "f");
        }
    }
};

let values = [...g.f(),];

assertEq(hits, 2);

assertEq(values.toSource(), "[1]");
// Tests that NX works through the enabled toggle and adding/removing the
// global.

load(libdir + "asserts.js");
load(libdir + "debuggerNXHelper.js");

var g = newGlobal();
var dbg = new Debugger(g);

g.eval(`
       function f() { }
       var o = {
         get p() { },
         set p(x) { }
       };
       `);

var handlers = [() => { g.f(); },
                () => { g.o.p } ,
                () => { g.o.p = 42; }];

function testHookEnabled(hookName, trigger) {
  for (var h of handlers) {
    assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
    dbg.enabled = false;
    h();
    dbg.enabled = true;
    assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
  }
}

function testHookRemoval(hookName, trigger) {
  for (var h of handlers) {
    assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
    dbg.removeDebuggee(g);
    h();
    dbg.addDebuggee(g);
    assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
  }
}

testDebuggerHooksNX(dbg, g, testHookEnabled);
testDebuggerHooksNX(dbg, g, testHookRemoval);

vs

load(libdir + "asserts.js");

load(libdir + "debuggerNXHelper.js");

var g = newGlobal();

var dbg = new Debugger(g);

g.eval(`
       function f() { }
       var o = {
         get p() { },
         set p(x) { }
       };
       `);

var handlers = [()  => {
    g.f();
}, ()  => {
    g.o.p;
}, ()  => {
    g.o.p = 42;
},];

function testHookEnabled(hookName, trigger) {
    for (h of handlers) {
        assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);

        dbg.enabled = false;

        h();

        dbg.enabled = true;

        assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
    }
}

function testHookRemoval(hookName, trigger) {
    for (h of handlers) {
        assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);

        dbg.removeDebuggee(g);

        h();

        dbg.addDebuggee(g);

        assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
    }
}

testDebuggerHooksNX(dbg, g, testHookEnabled);

testDebuggerHooksNX(dbg, g, testHookRemoval);
// |jit-test| error:SyntaxError

// Binary: cache/js-dbg-64-1fd6c40d3852-linux
// Flags: --ion-eager
//

var ary = ["\u001Cfoo", "\u001Dfoo", "\u001Efoo", "\u001Ffoo"];
for (var i in ary) {
  ary[Number(i)].search("var MYVAR='077';++MYVAR")
}

vs

var ary = ["\u001Cfoo", "\u001Dfoo", "\u001Efoo", "\u001Ffoo",];

for (i in ary) {
    ary[Number(i)].search("var MYVAR='077';++MYVAR");
}
// Arrow functions have a .length property like ordinary functions.

assertEq((a => a).hasOwnProperty("length"), true);

assertEq((a => a).length, 1);
assertEq((() => 0).length, 0);
assertEq(((a) => 0).length, 1);
assertEq(((a, b) => 0).length, 2);

assertEq(((...arr) => arr).length, 0);
assertEq(((a=1, b=2) => 0).length, 0);

vs

assertEq(a => a.hasOwnProperty("length"), true);

assertEq(a => a.length, 1);

assertEq(()  => 0.length, 0);

assertEq(a => 0.length, 1);

assertEq((a, b)  => 0.length, 2);

assertEq(arr => arr.length, 0);

assertEq((a = 1, b = 2)  => 0.length, 0);
// |jit-test| skip-if: helperThreadCount() === 0

// Let a few threads hammer on memory with atomics to provoke errors
// in exclusion work.  This test is not 100% fail-safe: the test may
// pass despite a bug, but this is unlikely.

// Map an Int32Array on shared memory.  The first location is used as
// a counter, each worker counts up on exit and the main thread will
// wait until the counter reaches the number of workers.  The other
// elements are contended accumulators where we count up and down very
// rapidly and for a long time, any failure in mutual exclusion should
// lead to errors in the result.  (For example, the test fails almost
// immediately when I disable simulation of mutual exclusion in the
// ARM simulator.)

const numWorkers = 4;           // You're not meant to change this
const iterCount = 255;          // Nor this
const sabLength = 1024;         // Nor this

const oddResult = (function () {
    var v = 0;
    for ( var j=0 ; j < numWorkers ; j++ )
        v |= (iterCount << (8 * j));
    return v;
})();

const evenResult = 0;

const sab = new SharedArrayBuffer(sabLength);

setSharedObject(sab);

const iab = new Int32Array(sab);

function testRun(limit) {
    console.log("Limit = " + limit);

    // Fork off workers to hammer on memory.
    for ( var i=0 ; i < numWorkers ; i++ ) {
        evalInWorker(`
                     const iab = new Int32Array(getSharedObject());
                     const v = 1 << (8 * ${i});
                     for ( var i=0 ; i < ${limit} ; i++ ) {
                         for ( var k=0 ; k < ${iterCount} ; k++ ) {
                             if (i & 1) {
                                 for ( var j=1 ; j < iab.length ; j++ )
                                     Atomics.sub(iab, j, v);
                             }
                             else {
                                 for ( var j=1 ; j < iab.length ; j++ )
                                     Atomics.add(iab, j, v);
                             }
                         }
                     }
                     Atomics.add(iab, 0, 1);
                     `);
    }

    // Wait...
    while (Atomics.load(iab, 0) != numWorkers)
        ;
    Atomics.store(iab, 0, 0);

    // Check the results and clear the array again.
    const v = (limit & 1) ? oddResult : evenResult;
    for ( var i=1 ; i < iab.length ; i++ ) {
        assertEq(iab[i], v);
        iab[i] = 0;
    }
}

// Under some configurations the test can take a while to run (and may
// saturate the CPU since it runs four workers); try not to time out.

var then = new Date();
testRun(1);
if (new Date() - then < 20000) {
    testRun(2);
    if (new Date() - then < 30000) {
	testRun(3);
    }
}

vs

const numWorkers = 4;

const iterCount = 255;

const sabLength = 1024;

const oddResult = (function() {
    var v = 0;
    for (let j = 0;j < numWorkers;j++) v |= iterCount << 8 * j;
    return v;
})();

const evenResult = 0;

const sab = new SharedArrayBuffer(sabLength);

setSharedObject(sab);

const iab = new Int32Array(sab);

function testRun(limit) {
    console.log("Limit = " + limit);
    for (let i = 0;i < numWorkers;i++) {
        evalInWorker(`
                     const iab = new Int32Array(getSharedObject());
                     const v = 1 << (8 * ${i});
                     for ( var i=0 ; i < {limit} ; i++ ) {
                         for ( var k=0 ; k < {iterCount} ; k++ ) {
                             if (i & 1) {
                                 for ( var j=1 ; j < iab.length ; j++ )
                                     Atomics.sub(iab, j, v);
                             }
                             else {
                                 for ( var j=1 ; j < iab.length ; j++ )
                                     Atomics.add(iab, j, v);
                             }
                         }
                     }
                     Atomics.add(iab, 0, 1);
                     `);
    }
    while (Atomics.load(iab, 0) != numWorkers) ;
    Atomics.store(iab, 0, 0);
    const v = limit & 1 ? oddResult : evenResult;
    for (let i = 1;i < iab.length;i++) {
        assertEq(iab[i], v);

        iab[i] = 0;
    }
}

var then = new Date();

testRun(1);

if (new Date() - then < 20000) {
    testRun(2);

    if (new Date() - then < 30000) {
        testRun(3);
    }
}
(function() {
    a = (b => eval("0; [arguments]"))();
})();

vs

(function() {
    a = b => eval("0; [arguments]")();
})();
// Returning and throwing objects.

load(libdir + "asserts.js");

var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("(" + function () {
        var how, what;
        var dbg = new Debugger(debuggeeGlobal);
        dbg.onDebuggerStatement = function (frame) {
            if (frame.callee.name === "configure") {
                how = frame.arguments[0];
                what = frame.arguments[1];
            } else {
                var resume = {};
                resume[how] = what;
                return resume;
            }
        };
    } + ")();");

function configure(how, what) { debugger; }
function fire() { debugger; }

var d = new Date;
configure('return', d);
assertEq(fire(), d);
configure('return', Math);
assertEq(fire(), Math);

var x = new Error('oh no what are you doing');
configure('throw', x);
assertThrowsValue(fire, x);
configure('throw', parseInt);
assertThrowsValue(fire, parseInt);

vs

load(libdir + "asserts.js");

var g = newGlobal();

g.debuggeeGlobal = this;

g.eval("(" + (function() {
    var how, what;
    var dbg = new Debugger(debuggeeGlobal);
    dbg.onDebuggerStatement = function(frame) {
        if (frame.callee.name === "configure") {
            how = frame.arguments[0];

            what = frame.arguments[1];
        } else {
            var resume = {            };

            resume[how] = what;

            return resume;
        }
    };
}) + ")();");

function configure(how, what) {
    debugger;;
}

function fire() {
    debugger;;
}

var d = new Date();

configure('return', d);

assertEq(fire(), d);

configure('return', Math);

assertEq(fire(), Math);

var x = new Error('oh no what are you doing');

configure('throw', x);

assertThrowsValue(fire, x);

configure('throw', parseInt);

assertThrowsValue(fire, parseInt);
// Binary: cache/js-dbg-64-1fd6c40d3852-linux
// Flags: --ion-eager
//

var cnName = 'name';
var cnNameGetter = function() {this.nameGETS++; return this._name;};
obj = (new (function  (  )  {  }  )         );
obj.__defineGetter__(cnName, cnNameGetter);
function lameFunc(x, y) {
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (obj.name) + (y >> 16) + (lsw >> 16);
}
function runSomeTimes(func, iters) {
    for (var i = 0; i < iters; ++i) {
        result = func(42, 42);
    }
}
for (var i = 0; i < 11000; ++i)
    runSomeTimes(lameFunc, 1);

vs

var cnName = 'name';

var cnNameGetter = (function() {
    this.nameGETS++;
    return this._name;
});

obj = new (function() { })();

obj.__defineGetter__(cnName, cnNameGetter);

function lameFunc(x, y) {
    var lsw = x & 0xFFFF + y & 0xFFFF;
    var msw = obj.name + y >> 16 + lsw >> 16;
}

function runSomeTimes(func, iters) {
    for (let i = 0;i < iters;++i) {
        result = func(42, 42);
    }
}

for (let i = 0;i < 11000;++i) runSomeTimes(lameFunc, 1);
// getLineOffsets works with extended instructions, such as JSOP_GOTOX.

var g = newGlobal();
g.line0 = null;
var dbg = Debugger(g);
var where;
dbg.onDebuggerStatement = function (frame) {
    var s = frame.script;
    var offs;
    var lineno = g.line0 + where;
    offs = s.getLineOffsets(lineno);
    for (var i = 0; i < offs.length; i++) {
        assertEq(s.getOffsetLocation(offs[i]).lineNumber, lineno);
        s.setBreakpoint(offs[i], {hit: function (frame) { g.log += 'B'; }});
    }
    g.log += 'A';
};

function test(s) {
    assertEq(s.charAt(s.length - 1) !== '\n', true);
    var count = s.split(/\n/).length;  // number of lines in s
    g.i = 0;
    g.log = '';
    where = 1 + count;
    g.eval("line0 = Error().lineNumber;\n" +
           "debugger;\n" +          // line0 + 1
           s +                      // line0 + 2 ... line0 + where
           " log += 'C';\n");
    assertEq(g.log, 'ABC');
}

function repeat(s) {
    return Array((1 << 14) + 1).join(s);  // 16K copies of s
}
var long_expr = "i" + repeat(" + i");
var long_throw_stmt = "throw " + long_expr + ";\n";

// long break (JSOP_GOTOX)
test("for (;;) {\n" +
     "    if (i === 0)\n" +
     "        break;\n" +
     "    " + long_throw_stmt +
     "}");

// long continue (JSOP_GOTOX)
test("do {\n" +
     "    if (i === 0)\n" +
     "        continue;\n" +
     "    " + long_throw_stmt +
     "} while (i !== 0);");

// long if consequent (JSOP_IFEQX)
test("if (i === 2) {\n" +
     "    " + long_throw_stmt +
     "}");

// long catch-block with finally (JSOP_GOSUBX)
test("try {\n" +
     "    i = 0;\n" +
     "} catch (exc) {\n" +
     "    throw " + long_expr + ";\n" +
     "} finally {\n" +
     "    i = 1;\n" +
     "}");

// long case (JSOP_TABLESWITCHX)
test("switch (i) {\n" +
     "  default:\n" +
     "  case 1: " + long_throw_stmt +
     "  case 0: i++; }");

test("switch (i) {\n" +
     "  case 1: case 2: case 3: " + long_throw_stmt +
     "  default: i++; }");

// long case (JSOP_LOOKUPSWITCHX)
test("switch ('' + i) {\n" +
     "  default:\n" +
     "  case '1': " + long_throw_stmt +
     "  case '0': i++; }");

test("switch (i) {\n" +
     "  case '1': case '2': case '3': " + long_throw_stmt +
     "  default: i++; }");

// long case or case-expression (JSOP_CASEX)
test("switch (i) {\n" +
     "  case i + 1 - i:\n" +
     "  default:\n" +
     "    " + long_throw_stmt +
     "  case i + i:\n" +
     "    i++; break; }");

// long case when JSOP_CASE is used (JSOP_DEFAULTX)
test("switch (i) {\n" +
     "  case i + 1 - i:\n" +
     "    " + long_throw_stmt +
     "  default:\n" +
     "    i++; break; }");

vs

var g = newGlobal();

g.line0 = null;

var dbg = Debugger(g);

var where;

dbg.onDebuggerStatement = (function(frame) {
    var s = frame.script;
    var offs;
    var lineno = g.line0 + where;
    offs = s.getLineOffsets(lineno);
    for (let i = 0;i < offs.length;i++) {
        assertEq(s.getOffsetLocation(offs[i]).lineNumber, lineno);

        s.setBreakpoint(offs[i], {
            hit: function(frame) {
                g.log += 'B';
            },
        });
    }
    g.log += 'A';
});

function test(s) {
    assertEq(s.charAt(s.length - 1) !== '\n', true);
    var count = s.split(/\n/).length;
    g.i = 0;
    g.log = '';
    where = 1 + count;
    g.eval("line0 = Error().lineNumber;\n" + "debugger;\n" + s + " log += 'C';\n");
    assertEq(g.log, 'ABC');
}

function repeat(s) {
    return Array(1 << 14 + 1).join(s);
}

var long_expr = "i" + repeat(" + i");

var long_throw_stmt = "throw " + long_expr + ";\n";

test("for (;;) {\n" + "    if (i === 0)\n" + "        break;\n" + "    " + long_throw_stmt + "}");

test("do {\n" + "    if (i === 0)\n" + "        continue;\n" + "    " + long_throw_stmt + "} while (i !== 0);");

test("if (i === 2) {\n" + "    " + long_throw_stmt + "}");

test("try {\n" + "    i = 0;\n" + "} catch (exc) {\n" + "    throw " + long_expr + ";\n" + "} finally {\n" + "    i = 1;\n" + "}");

test("switch (i) {\n" + "  default:\n" + "  case 1: " + long_throw_stmt + "  case 0: i++; }");

test("switch (i) {\n" + "  case 1: case 2: case 3: " + long_throw_stmt + "  default: i++; }");

test("switch ('' + i) {\n" + "  default:\n" + "  case '1': " + long_throw_stmt + "  case '0': i++; }");

test("switch (i) {\n" + "  case '1': case '2': case '3': " + long_throw_stmt + "  default: i++; }");

test("switch (i) {\n" + "  case i + 1 - i:\n" + "  default:\n" + "    " + long_throw_stmt + "  case i + i:\n" + "    i++; break; }");

test("switch (i) {\n" + "  case i + 1 - i:\n" + "    " + long_throw_stmt + "  default:\n" + "    i++; break; }");
(function(a) {
    "use asm"
    var Infinity = a.Infinity
    function f() {
        Infinity - (2 ? (1. / .0) : +0)
    }
    return f
})(this)()

vs

(function(a) {
    "use asm";
    var Infinity = a.Infinity;
    function f() {
        Infinity - 2 ? 1. / .0 : +0;
    }
    return f;
})(this)();
/*
 * Don't throw a type error if the trap reports an undefined property as
 * non-present, regardless of extensibility.
 */
var target = {};
Object.preventExtensions(target);

var handler = { has: () => false };

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    assertEq('foo' in p, false);
    assertEq(Symbol.iterator in p, false);
}

vs

var target = ({});

Object.preventExtensions(target);

var handler = ({
    has: ()  => false,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    assertEq('foo' in p, false);

    assertEq(Symbol.iterator in p, false);
}
enableGeckoProfiling();
for (var j = 0; j < 1000; ++j) {
  (function(stdlib) {
    "use asm";
    var pow = stdlib.Math.pow;
    function f() {
        return +pow(.0, .0)
    }
    return f;
})(this)()
}

vs

enableGeckoProfiling();

for (let j = 0;j < 1000;++j) {
    function(stdlib) {
        "use asm";
        var pow = stdlib.Math.pow;
        function f() {
            return +pow(.0, .0);
        }
        return f;
    }(this)();
}
// IteratorClose in for-await-of with block-scoped function.

// Non-local-jump without target.

(async function() {
    for await (let c of []) {
        function f() {};
        return;
    }
})();
(async function() {
    for await (let c of []) {
        function f() {};
        break;
    }
})();
(async function() {
    for await (let c of []) {
        function f() {};
        continue;
    }
})();

// Non-local-jump with target.

(async function() {
    for (let x of []) {
        x: for (let y of []) {
            for await (let c of []) {
                function f() {};
                return;
            }
        }
    }
})();
(async function() {
    for (let x of []) {
        x: for (let y of []) {
            for await (let c of []) {
                function f() {};
                break x;
            }
        }
    }
})();
(async function() {
    for (let x of []) {
        x: for (let y of []) {
            for await (let c of []) {
                function f() {};
                continue x;
            }
        }
    }
})();

(async function() {
    for await (let x of []) {
        x: for await (let y of []) {
            for await (let c of []) {
                function f() {};
                return;
            }
        }
    }
})();
(async function() {
    for await (let x of []) {
        x: for await (let y of []) {
            for await (let c of []) {
                function f() {};
                break x;
            }
        }
    }
})();
(async function() {
    for await (let x of []) {
        x: for await (let y of []) {
            for await (let c of []) {
                function f() {};
                continue x;
            }
        }
    }
})();

vs

(async function() {
    for (c of []) {
        function f() { }

        ;

        return;
    }
})();

(async function() {
    for (c of []) {
        function f() { }

        ;

        break;
    }
})();

(async function() {
    for (c of []) {
        function f() { }

        ;

        continue;
    }
})();

(async function() {
    for (x of []) {
        x: for (y of []) {
            for (c of []) {
                function f() { }

                ;

                return;
            }
        }

    }
})();

(async function() {
    for (x of []) {
        x: for (y of []) {
            for (c of []) {
                function f() { }

                ;

                break x;
            }
        }

    }
})();

(async function() {
    for (x of []) {
        x: for (y of []) {
            for (c of []) {
                function f() { }

                ;

                continue x;
            }
        }

    }
})();

(async function() {
    for (x of []) {
        x: for (y of []) {
            for (c of []) {
                function f() { }

                ;

                return;
            }
        }

    }
})();

(async function() {
    for (x of []) {
        x: for (y of []) {
            for (c of []) {
                function f() { }

                ;

                break x;
            }
        }

    }
})();

(async function() {
    for (x of []) {
        x: for (y of []) {
            for (c of []) {
                function f() { }

                ;

                continue x;
            }
        }

    }
})();
// Test that Ion->Baseline in-place debug mode bailout can recover the iterator
// from the snapshot in a for-of loop.

g = newGlobal();
g.parent = this;
g.eval("Debugger(parent).onExceptionUnwind=(function() {})");
function* throwInNext() {
  yield 1;
  yield 2;
  yield 3;
  throw 42;
}

function f() {
  for (var o of throwInNext());
}

var log = "";
try {
  f();
} catch (e) {
  log += e;
}

assertEq(log, "42");

vs

g = newGlobal();

g.parent = this;

g.eval("Debugger(parent).onExceptionUnwind=(function() {})");

function *throwInNext() {
    yield 1;
    yield 2;
    yield 3;
    throw 42;
}

function f() {
    for (o of throwInNext()) ;
}

var log = "";

try {
    f();
} catch (e) {
    log += e;
}

assertEq(log, "42");
/*
 * Call the trap with the handler as the this value, the target as the first
 * argument, the name of the property as the second argument, and the receiver
 * as the third argument
 */
var target = {};
for (var key of ['foo', Symbol.iterator]) {
    handler = {};
    for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
        handler.get =
            function (target1, name, receiver) {
                assertEq(this, handler);
                assertEq(target1, target);
                assertEq(name, key);
                assertEq(receiver, p);
                called = true;
            };
        var called = false;
        assertEq(p[key], undefined);
        assertEq(called, true);
    }
}

vs

var target = ({});

for (key of ['foo', Symbol.iterator,]) {
    handler = {    };

    for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
        handler.get = function(target1, name, receiver) {
            assertEq(this, handler);
            assertEq(target1, target);
            assertEq(name, key);
            assertEq(receiver, p);
            called = true;
        };

        var called = false;

        assertEq(p[key], undefined);

        assertEq(called, true);
    }
}
// |jit-test| error: Error: can't start debugging: a debuggee script is on the stack

var g = newGlobal();
var dbg = Debugger(g);

function loop(i) {
  var n = 0;
  for (n = 0; n < i; n++)
    debugger;
}
g.eval(loop.toSource());

var countDown = 20;
dbg.onDebuggerStatement = function (f) {
  // Should throw an error.
  if (countDown > 0 && --countDown == 0) {
    dbg.collectCoverageInfo = !dbg.collectCoverageInfo;
  }
};

dbg.collectCoverageInfo = true;
g.eval("loop("+ (2 * countDown) +");");

vs

var g = newGlobal();

var dbg = Debugger(g);

function loop(i) {
    var n = 0;
    for (n = 0;n < i;n++) debugger;;
}

g.eval(loop.toSource());

var countDown = 20;

dbg.onDebuggerStatement = (function(f) {
    if (countDown > 0 && --countDown == 0) {
        dbg.collectCoverageInfo = !dbg.collectCoverageInfo;
    }
});

dbg.collectCoverageInfo = true;

g.eval("loop(" + 2 * countDown + ");");
// Test cases when a SavedFrame or one of its ancestors have a principal that is
// not subsumed by the caller's principal, when async parents are present.

function checkVisibleStack(stackFrame, expectedFrames) {
  // We check toString separately from properties like asyncCause to check that
  // it walks the physical SavedFrame chain consistently with the properties.
  var stringFrames = stackFrame.toString().split("\n");

  while (expectedFrames.length) {
    let expectedFrame = expectedFrames.shift();
    let stringFrame = stringFrames.shift();

    // Check the frame properties.
    assertEq(stackFrame.functionDisplayName, expectedFrame.name);
    assertEq(stackFrame.asyncCause, expectedFrame.asyncCause);

    // Check the stringified version.
    let expectedStart =
      (expectedFrame.asyncCause ? expectedFrame.asyncCause + "*" : "") +
      expectedFrame.name;
    assertEq(stringFrame.replace(/@.*$/, ""), expectedStart);

    // If the next frame has an asyncCause, it should be an asyncParent.
    if (expectedFrames.length && expectedFrames[0].asyncCause) {
      assertEq(stackFrame.parent, null);
      stackFrame = stackFrame.asyncParent;
    } else {
      assertEq(stackFrame.asyncParent, null);
      stackFrame = stackFrame.parent;
    }
  }
}

var low = newGlobal({ principal: 0 });
var high = newGlobal({ principal: 0xfffff });

// Test with synchronous cross-compartment calls.
//
// With arrows representing child-to-parent links, and fat arrows representing
// child-to-async-parent links, create a SavedFrame stack like this:
//
//     low.e -> high.d => high.c => high.b -> low.a
//
// This stack captured in function `e` would be seen in its complete version if
// accessed by `high`'s compartment, while in `low`'s compartment it would look
// like this:
//
//     low.e => low.a
//
// The asyncCause seen on `low.a` above should not leak information about the
// real asyncCause on `high.c` and `high.d`.
//
// The stack captured in function `d` would be seen in its complete version if
// accessed by `high`'s compartment, while in `low`'s compartment it would look
// like this:
//
//     low.a

// We'll move these functions into the right globals below before invoking them.
function a() {
  b();
}
function b() {
  callFunctionWithAsyncStack(c, saveStack(), "BtoC");
}
function c() {
  callFunctionWithAsyncStack(d, saveStack(), "CtoD");
}
function d() {
  let stackD = saveStack();

  print("high.checkVisibleStack(stackD)");
  checkVisibleStack(stackD, [
    { name: "d", asyncCause: null   },
    { name: "c", asyncCause: "CtoD" },
    { name: "b", asyncCause: "BtoC" },
    { name: "a", asyncCause: null   },
  ]);

  let stackE = e(saveStack(0, low));

  print("high.checkVisibleStack(stackE)");
  checkVisibleStack(stackE, [
    { name: "e", asyncCause: null   },
    { name: "d", asyncCause: null   },
    { name: "c", asyncCause: "CtoD" },
    { name: "b", asyncCause: "BtoC" },
    { name: "a", asyncCause: null   },
  ]);
}
function e(stackD) {
  print("low.checkVisibleStack(stackD)");
  checkVisibleStack(stackD, [
    { name: "a", asyncCause: "Async" },
  ]);

  let stackE = saveStack();

  print("low.checkVisibleStack(stackE)");
  checkVisibleStack(stackE, [
    { name: "e", asyncCause: null    },
    { name: "a", asyncCause: "Async" },
  ]);

  return saveStack(0, high);
}

// Test with asynchronous cross-compartment calls and shared frames.
//
// With arrows representing child-to-parent links, and fat arrows representing
// child-to-async-parent links, create a SavedFrame stack like this:
//
//     low.x => high.v => low.u
//     low.y -> high.v => low.u
//     low.z => high.w -> low.u
//
// This stack captured in functions `x`, `y`, and `z` would be seen in its
// complete version if accessed by `high`'s compartment, while in `low`'s
// compartment it would look like this:
//
//     low.x => low.u
//     low.y => low.u
//     low.z => low.u
//
// The stack captured in function `v` would be seen in its complete version if
// accessed by `high`'s compartment, while in `low`'s compartment it would look
// like this:
//
//     low.u

// We'll move these functions into the right globals below before invoking them.
function u() {
  callFunctionWithAsyncStack(v, saveStack(), "UtoV");
  w();
}
function v() {
  let stackV = saveStack();
  print("high.checkVisibleStack(stackV)");
  checkVisibleStack(stackV, [
    { name: "v", asyncCause: null   },
    { name: "u", asyncCause: "UtoV" },
  ]);

  let stack = saveStack(0, low);
  function xToCall() { return x(stack);};

  let stackX = callFunctionWithAsyncStack(xToCall, saveStack(), "VtoX");

  print("high.checkVisibleStack(stackX)");
  checkVisibleStack(stackX, [
    { name: "x", asyncCause: null   },
    { name: "xToCall", asyncCause: null },
    { name: "v", asyncCause: "VtoX" },
    { name: "u", asyncCause: "UtoV" },
  ]);

  let stackY = y();

  print("high.checkVisibleStack(stackY)");
  checkVisibleStack(stackY, [
    { name: "y", asyncCause: null   },
    { name: "v", asyncCause: null   },
    { name: "u", asyncCause: "UtoV" },
  ]);
}
function w() {
  let stackZ = callFunctionWithAsyncStack(z, saveStack(), "WtoZ");

  print("high.checkVisibleStack(stackZ)");
  checkVisibleStack(stackZ, [
    { name: "z", asyncCause: null   },
    { name: "w", asyncCause: "WtoZ" },
    { name: "u", asyncCause: null   },
  ]);
}
function x(stackV) {
  print("low.checkVisibleStack(stackV)");
  checkVisibleStack(stackV, [
    { name: "u", asyncCause: "UtoV" },
  ]);

  let stackX = saveStack();

  print("low.checkVisibleStack(stackX)");
  checkVisibleStack(stackX, [
    { name: "x", asyncCause: null   },
    { name: "u", asyncCause: "UtoV" },
  ]);

  return saveStack(0, high);
}

function y() {
  let stackY = saveStack();

  print("low.checkVisibleStack(stackY)");
  checkVisibleStack(stackY, [
    { name: "y", asyncCause: null   },
    { name: "u", asyncCause: "UtoV" },
  ]);

  return saveStack(0, high);
}
function z() {
  let stackZ = saveStack();

  print("low.checkVisibleStack(stackZ)");
  checkVisibleStack(stackZ, [
    { name: "z", asyncCause: null    },
    { name: "u", asyncCause: "Async" },
  ]);

  return saveStack(0, high);
}

// Split the functions in their respective globals.
low .eval(a.toSource());
high.eval(b.toSource());
high.eval(c.toSource());
high.eval(d.toSource());
low .eval(e.toSource());

low .b = high.b;
high.e = low .e;

low .eval(u.toSource());
high.eval(v.toSource());
high.eval(w.toSource());
low .eval(x.toSource());
low .eval(y.toSource());
low .eval(z.toSource());

low .v = high.v;
low .w = high.w;
high.x = low .x;
high.y = low .y;
high.z = low .z;

low .high = high;
high.low  = low;

low .eval(checkVisibleStack.toSource());
high.eval(checkVisibleStack.toSource());

// Execute the tests.
low.a();
low.u();

vs

function checkVisibleStack(stackFrame, expectedFrames) {
    var stringFrames = stackFrame.toString().split("\n");
    while (expectedFrames.length) {
        let expectedFrame = expectedFrames.shift();

        let stringFrame = stringFrames.shift();

        assertEq(stackFrame.functionDisplayName, expectedFrame.name);

        assertEq(stackFrame.asyncCause, expectedFrame.asyncCause);

        let expectedStart = expectedFrame.asyncCause ? expectedFrame.asyncCause + "*" : "" + expectedFrame.name;

        assertEq(stringFrame.replace(/@.*$/, ""), expectedStart);

        if (expectedFrames.length && expectedFrames[0].asyncCause) {
            assertEq(stackFrame.parent, null);

            stackFrame = stackFrame.asyncParent;
        } else {
            assertEq(stackFrame.asyncParent, null);

            stackFrame = stackFrame.parent;
        }
    }
}

var low = newGlobal(({
    principal: 0,
}));

var high = newGlobal(({
    principal: 0xfffff,
}));

function a() {
    b();
}

function b() {
    callFunctionWithAsyncStack(c, saveStack(), "BtoC");
}

function c() {
    callFunctionWithAsyncStack(d, saveStack(), "CtoD");
}

function d() {
    let stackD = saveStack();
    print("high.checkVisibleStack(stackD)");
    checkVisibleStack(stackD, [{
        name: "d",
        asyncCause: null,
    }, {
        name: "c",
        asyncCause: "CtoD",
    }, {
        name: "b",
        asyncCause: "BtoC",
    }, {
        name: "a",
        asyncCause: null,
    },]);
    let stackE = e(saveStack(0, low));
    print("high.checkVisibleStack(stackE)");
    checkVisibleStack(stackE, [{
        name: "e",
        asyncCause: null,
    }, {
        name: "d",
        asyncCause: null,
    }, {
        name: "c",
        asyncCause: "CtoD",
    }, {
        name: "b",
        asyncCause: "BtoC",
    }, {
        name: "a",
        asyncCause: null,
    },]);
}

function e(stackD) {
    print("low.checkVisibleStack(stackD)");
    checkVisibleStack(stackD, [{
        name: "a",
        asyncCause: "Async",
    },]);
    let stackE = saveStack();
    print("low.checkVisibleStack(stackE)");
    checkVisibleStack(stackE, [{
        name: "e",
        asyncCause: null,
    }, {
        name: "a",
        asyncCause: "Async",
    },]);
    return saveStack(0, high);
}

function u() {
    callFunctionWithAsyncStack(v, saveStack(), "UtoV");
    w();
}

function v() {
    let stackV = saveStack();
    print("high.checkVisibleStack(stackV)");
    checkVisibleStack(stackV, [{
        name: "v",
        asyncCause: null,
    }, {
        name: "u",
        asyncCause: "UtoV",
    },]);
    let stack = saveStack(0, low);
    function xToCall() {
        return x(stack);
    }
    ;
    let stackX = callFunctionWithAsyncStack(xToCall, saveStack(), "VtoX");
    print("high.checkVisibleStack(stackX)");
    checkVisibleStack(stackX, [{
        name: "x",
        asyncCause: null,
    }, {
        name: "xToCall",
        asyncCause: null,
    }, {
        name: "v",
        asyncCause: "VtoX",
    }, {
        name: "u",
        asyncCause: "UtoV",
    },]);
    let stackY = y();
    print("high.checkVisibleStack(stackY)");
    checkVisibleStack(stackY, [{
        name: "y",
        asyncCause: null,
    }, {
        name: "v",
        asyncCause: null,
    }, {
        name: "u",
        asyncCause: "UtoV",
    },]);
}

function w() {
    let stackZ = callFunctionWithAsyncStack(z, saveStack(), "WtoZ");
    print("high.checkVisibleStack(stackZ)");
    checkVisibleStack(stackZ, [{
        name: "z",
        asyncCause: null,
    }, {
        name: "w",
        asyncCause: "WtoZ",
    }, {
        name: "u",
        asyncCause: null,
    },]);
}

function x(stackV) {
    print("low.checkVisibleStack(stackV)");
    checkVisibleStack(stackV, [{
        name: "u",
        asyncCause: "UtoV",
    },]);
    let stackX = saveStack();
    print("low.checkVisibleStack(stackX)");
    checkVisibleStack(stackX, [{
        name: "x",
        asyncCause: null,
    }, {
        name: "u",
        asyncCause: "UtoV",
    },]);
    return saveStack(0, high);
}

function y() {
    let stackY = saveStack();
    print("low.checkVisibleStack(stackY)");
    checkVisibleStack(stackY, [{
        name: "y",
        asyncCause: null,
    }, {
        name: "u",
        asyncCause: "UtoV",
    },]);
    return saveStack(0, high);
}

function z() {
    let stackZ = saveStack();
    print("low.checkVisibleStack(stackZ)");
    checkVisibleStack(stackZ, [{
        name: "z",
        asyncCause: null,
    }, {
        name: "u",
        asyncCause: "Async",
    },]);
    return saveStack(0, high);
}

low.eval(a.toSource());

high.eval(b.toSource());

high.eval(c.toSource());

high.eval(d.toSource());

low.eval(e.toSource());

low.b = high.b;

high.e = low.e;

low.eval(u.toSource());

high.eval(v.toSource());

high.eval(w.toSource());

low.eval(x.toSource());

low.eval(y.toSource());

low.eval(z.toSource());

low.v = high.v;

low.w = high.w;

high.x = low.x;

high.y = low.y;

high.z = low.z;

low.high = high;

high.low = low;

low.eval(checkVisibleStack.toSource());

high.eval(checkVisibleStack.toSource());

low.a();

low.u();
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap reports an existing own property as
 * non-existent on a non-extensible object
 */
var target = {};
Object.defineProperty(target, 'foo', {
    configurable: true
});
Object.preventExtensions(target);

var handler = { getOwnPropertyDescriptor: () => undefined };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    configurable: true,
}));

Object.preventExtensions(target);

var handler = ({
    getOwnPropertyDescriptor: ()  => undefined,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
load(libdir + "asserts.js");

// Throw TypeError if trap returns a property key multiple times.

var handler = { ownKeys : () => [ 'foo', 'foo' ] };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    ownKeys: ()  => ['foo', 'foo',],
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyNames(p), TypeError);
// onPop fires while the [[GeneratorState]] is still "executing".
//
// This test checks that Debugger doesn't accidentally make it possible to
// reenter a generator frame that's on the stack.

load(libdir + "asserts.js");

let g = newGlobal();
g.eval('function* f() { debugger; yield 1; debugger; yield 2; debugger; }');
let dbg = Debugger(g);
let genObj = g.f();

let hits = 0;
dbg.onDebuggerStatement = frame => {
    frame.onPop = completion => {
        dbg.removeDebuggee(g);  // avoid the DebuggeeWouldRun exception
        hits++;
        if (hits < 3) {
            // We're yielding. Calling .return(), .next(), or .throw() on a
            // generator that's currently on the stack fails with a TypeError.
            assertThrowsInstanceOf(() => genObj.next(), g.TypeError);
            assertThrowsInstanceOf(() => genObj.throw("fit"), g.TypeError);
            assertThrowsInstanceOf(() => genObj.return(), g.TypeError);
        } else {
            // This time we're returning. The generator has already been
            // closed, so its methods work but are basically no-ops.
            let result = genObj.next();
            assertEq(result.done, true);
            assertEq(result.value, undefined);

            assertThrowsValue(() => genObj.throw("fit"), "fit");

            result = genObj.return();
            assertEq(result.done, true);
            assertEq(result.value, undefined);
        }
        dbg.addDebuggee(g);
    };
};

for (let x of genObj) {}
assertEq(hits, 3);

vs

load(libdir + "asserts.js");

let g = newGlobal();

g.eval('function* f() { debugger; yield 1; debugger; yield 2; debugger; }');

let dbg = Debugger(g);

let genObj = g.f();

let hits = 0;

dbg.onDebuggerStatement = frame => {
    frame.onPop = completion => {
        dbg.removeDebuggee(g);
        hits++;
        if (hits < 3) {
            assertThrowsInstanceOf(()  => genObj.next(), g.TypeError);

            assertThrowsInstanceOf(()  => genObj.throw("fit"), g.TypeError);

            assertThrowsInstanceOf(()  => genObj.return(), g.TypeError);
        } else {
            let result = genObj.next();

            assertEq(result.done, true);

            assertEq(result.value, undefined);

            assertThrowsValue(()  => genObj.throw("fit"), "fit");

            result = genObj.return();

            assertEq(result.done, true);

            assertEq(result.value, undefined);
        }
        dbg.addDebuggee(g);
    };
};

for (x of genObj) { 
    
}

assertEq(hits, 3);
load(libdir + 'asserts.js');

function test() {
  let strcut = ctypes.StructType("a", [ { "x": ctypes.int32_t, } ])();
  for (let arg of [1, undefined, null, false, {}, [], Symbol("foo")]) {
    assertThrowsInstanceOf(() => { struct.addressOfField(arg); },
                           Error);
  }
}

if (typeof ctypes === "object")
  test();

vs

load(libdir + 'asserts.js');

function test() {
    let strcut = ctypes.StructType("a", [{
        "x": ctypes.int32_t,
    },])();
    for (arg of [1, undefined, null, false, {    }, [], Symbol("foo"),]) {
        assertThrowsInstanceOf(()  => {
            struct.addressOfField(arg);
        }, Error);
    }
}

if (typeof ctypes === "object") test();

load(libdir + "asserts.js");

// Throw a TypeError if the trap skips a non-configurable enumerable property
var target = {};
Object.defineProperty(target, 'foo', {
    enumerable: true,
    configurable: false
});

var handler = { ownKeys: () => [] };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.keys(p), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    enumerable: true,
    configurable: false,
}));

var handler = ({
    ownKeys: ()  => [],
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.keys(p), TypeError);
// Test that you can't call the SavedFrame constructor and can only use
// SavedFrame's getters on SavedFrame instances.

load(libdir + "asserts.js");

let proto = Object.getPrototypeOf(saveStack());

// Can't create new SavedFrame instances by hand.
print("Testing constructor");
assertThrowsInstanceOf(() => {
  new proto.constructor();
}, TypeError);

for (let p of ["source", "line", "column", "functionDisplayName", "parent"]) {
  print("Testing getter: " + p);
  // The getters shouldn't work on the prototype.
  assertThrowsInstanceOf(() => proto[p], TypeError);

  // Nor should they work on random objects.
  let o = {};
  Object.defineProperty(o, p, Object.getOwnPropertyDescriptor(proto, p));
  assertThrowsInstanceOf(() => o[p], TypeError);
}

vs

load(libdir + "asserts.js");

let proto = Object.getPrototypeOf(saveStack());

print("Testing constructor");

assertThrowsInstanceOf(()  => {
    new proto.constructor();
}, TypeError);

for (p of ["source", "line", "column", "functionDisplayName", "parent",]) {
    print("Testing getter: " + p);

    assertThrowsInstanceOf(()  => proto[p], TypeError);

    let o = {    };

    Object.defineProperty(o, p, Object.getOwnPropertyDescriptor(proto, p));

    assertThrowsInstanceOf(()  => o[p], TypeError);
}
// Check that stepping doesn't make it look like unreachable code is running.

// Because our script source notes record only those bytecode offsets
// at which source positions change, the default behavior in the
// absence of a source note is to attribute a bytecode instruction to
// the same source location as the preceding instruction. When control
// flows from the preceding bytecode to the one we're emitting, that's
// usually plausible. But successors in the bytecode stream are not
// necessarily successors in the control flow graph. If the preceding
// bytecode was a back edge of a loop, or the jump at the end of a
// 'then' clause, its source position can be completely unrelated to
// that of its successor.
//
// We try to avoid showing such nonsense offsets to the user by
// requiring breakpoints and single-stepping to stop only at a line's
// entry points, as reported by Debugger.Script.prototype.getLineOffsets;
// and then ensuring that those entry points are all offsets mentioned
// explicitly in the source notes, and hence deliberately attributed
// to the given bytecode.
//
// This bit of JavaScript compiles to bytecode ending in a branch
// instruction whose source position is the body of an unreachable
// loop. The first instruction of the bytecode we emit following it
// will inherit this nonsense position, if we have not explicitly
// emitted a source note for said instruction.
//
// This test steps across such code and verifies that control never
// appears to enter the unreachable loop.

var bitOfCode = `debugger;                    // +0
                 if(false) {                  // +1
                   for(var b=0; b<0; b++) {   // +2
                      c = 2                   // +3
                    }                         // +4
                 }`;                          // +5

var g = newGlobal();
var dbg = Debugger(g);

g.eval("function nothing() { }\n");

var log = '';
dbg.onDebuggerStatement = function(frame) {
  let debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
  frame.onStep = function() {
    let foundLine = this.script.getOffsetLocation(this.offset).lineNumber;
    if (this.script.getLineOffsets(foundLine).indexOf(this.offset) >= 0) {
      log += (foundLine - debugLine).toString(16);
    }
  };
};

function testOne(name, body, expected) {
  print(name);
  log = '';
  g.eval(`function ${name} () { ${body} }`);
  g.eval(`${name}();`);
  assertEq(log, expected);
}



// Test the instructions at the end of a "try".
testOne("testTryFinally",
        `try {
           ${bitOfCode}
         } finally {            // +6
         }                      // +7
         nothing();             // +8
        `, "1689");

// The same but without a finally clause.
testOne("testTryCatch",
        `try {
           ${bitOfCode}
         } catch (e) {          // +6
         }                      // +7
         nothing();             // +8
        `, "189");

// Test the instructions at the end of a "catch".
testOne("testCatchFinally",
        `try {
           throw new TypeError();
         } catch (e) {
           ${bitOfCode}
         } finally {            // +6
         }                      // +7
         nothing();             // +8
        `, "1689");

// Test the instruction at the end of a "finally" clause.
testOne("testFinally",
        `try {
         } finally {
           ${bitOfCode}
         }                      // +6
         nothing();             // +7
        `, "178");

// Test the instruction at the end of a "then" clause.
testOne("testThen",
        `if (1 === 1) {
           ${bitOfCode}
         } else {               // +6
         }                      // +7
         nothing();             // +8
        `, "189");

// Test the instructions leaving a switch block.
testOne("testSwitch",
        `var x = 5;
         switch (x) {
           case 5:
             ${bitOfCode}
         }                      // +6
         nothing();             // +7
        `, "178");

vs

var bitOfCode = `debugger;                    // +0
                 if(false) {                  // +1
                   for(var b=0; b<0; b++) {   // +2
                      c = 2                   // +3
                    }                         // +4
                 }`;

var g = newGlobal();

var dbg = Debugger(g);

g.eval("function nothing() { }\n");

var log = '';

dbg.onDebuggerStatement = (function(frame) {
    let debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
    frame.onStep = function() {
        let foundLine = this.script.getOffsetLocation(this.offset).lineNumber;
        if (this.script.getLineOffsets(foundLine).indexOf(this.offset) >= 0) {
            log += foundLine - debugLine.toString(16);
        }
    };
});

function testOne(name, body, expected) {
    print(name);
    log = '';
    g.eval(`function ${name} () { {body} }`);
    g.eval(`${name}();`);
    assertEq(log, expected);
}

testOne("testTryFinally", `try {
           ${bitOfCode}
         } finally {            // +6
         }                      // +7
         nothing();             // +8
        `, "1689");

testOne("testTryCatch", `try {
           ${bitOfCode}
         } catch (e) {          // +6
         }                      // +7
         nothing();             // +8
        `, "189");

testOne("testCatchFinally", `try {
           throw new TypeError();
         } catch (e) {
           ${bitOfCode}
         } finally {            // +6
         }                      // +7
         nothing();             // +8
        `, "1689");

testOne("testFinally", `try {
         } finally {
           ${bitOfCode}
         }                      // +6
         nothing();             // +7
        `, "178");

testOne("testThen", `if (1 === 1) {
           ${bitOfCode}
         } else {               // +6
         }                      // +7
         nothing();             // +8
        `, "189");

testOne("testSwitch", `var x = 5;
         switch (x) {
           case 5:
             ${bitOfCode}
         }                      // +6
         nothing();             // +7
        `, "178");
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap does not report undefined for a non-configurable
 * accessor property that does not have a getter
 */
var target = {};
Object.defineProperty(target, 'foo', {
    set: function (value) {},
    configurable: false
});
var handler = { get: function (target, name, receiver) { return 'baz'; } };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(function () { p['foo'] }, TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    set: (function(value) { }),
    configurable: false,
}));

var handler = ({
    get: (function(target, name, receiver) {
        return 'baz';
    }),
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(function() {
    p['foo'];
}, TypeError);
// Test drainAllocationsLog() and constructor names.

const root = newGlobal();
const dbg = new Debugger();
const wrappedRoot = dbg.addDebuggee(root);

root.eval(
  `
  function Ctor() {}

  var nested = {};
  nested.Ctor = function () {};

  function makeInstance() {
    let LexicalCtor = function () {};
    return new LexicalCtor;
  }

  function makeObject() {
    let object = {};
    return object;
  }

  this.tests = [
    { name: "Ctor",                     fn: () => new Ctor             },
    { name: "nested.Ctor",              fn: () => new nested.Ctor      },
    { name: "LexicalCtor",              fn: () => makeInstance()       },
    { name: null,                       fn: () => ({})                 },
    { name: null,                       fn: () => (nested.object = {}) },
    { name: null,                       fn: () => makeObject()         },
  ];
  `
);

for (let { name, fn } of root.tests) {
  print(name);

  dbg.memory.trackingAllocationSites = true;

  fn();

  let entries = dbg.memory.drainAllocationsLog();
  let ctors = entries.map(e => e.constructor);
  assertEq(ctors.some(ctor => ctor === name), true);

  dbg.memory.trackingAllocationSites = false;
}

vs

const root = newGlobal();

const dbg = new Debugger();

const wrappedRoot = dbg.addDebuggee(root);

root.eval(`
  function Ctor() {}

  var nested = {};
  nested.Ctor = function () {};

  function makeInstance() {
    let LexicalCtor = function () {};
    return new LexicalCtor;
  }

  function makeObject() {
    let object = {};
    return object;
  }

  this.tests = [
    { name: "Ctor",                     fn: () => new Ctor             },
    { name: "nested.Ctor",              fn: () => new nested.Ctor      },
    { name: "LexicalCtor",              fn: () => makeInstance()       },
    { name: null,                       fn: () => ({})                 },
    { name: null,                       fn: () => (nested.object = {}) },
    { name: null,                       fn: () => makeObject()         },
  ];
  `);

for ({name, fn,} of root.tests) {
    print(name);

    dbg.memory.trackingAllocationSites = true;

    fn();

    let entries = dbg.memory.drainAllocationsLog();

    let ctors = entries.map(e => e.constructor);

    assertEq(ctors.some(ctor => ctor === name), true);

    dbg.memory.trackingAllocationSites = false;
}
var x = 2;
x = -(x == 3);

var y = "";
typeof(z) + typeof(eval("z = y"));

vs

var x = 2;

x = -x == 3;

var y = "";

typeof z + typeof eval("z = y");
// Assigning to the length property of a proxy to an array
// calls the proxy's defineProperty handler.

var a = [0, 1, 2, 3];
var p = new Proxy(a, {
    defineProperty(t, id, desc) {
        hits++;

        // ES6 draft rev 28 (2014 Oct 14) 9.1.9 step 5.e.i.
        // Since the property already exists, the system only changes
        // the value. desc is otherwise empty.
        assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
        assertEq(desc.value, 2);
        return true;
    }
});
var hits = 0;
p.length = 2;
assertEq(hits, 1);
assertEq(a.length, 4);
assertEq(a[2], 2);

vs

var a = [0, 1, 2, 3,];

var p = new Proxy(a, ({
    defineProperty: (function(t, id, desc) {
        hits++;
        assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
        assertEq(desc.value, 2);
        return true;
    }),
}));

var hits = 0;

p.length = 2;

assertEq(hits, 1);

assertEq(a.length, 4);

assertEq(a[2], 2);
// Breakpoints work in non-compile-and-go code. Bug 738479.

var g = newGlobal();
g.s = '';
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
g.evaluate(
    "function f() {\n" +  // fscript.startLine
    "    s += 'a';\n" +   // fscript.startLine + 1
    "    s += 'b';\n" +   // fscript.startLine + 2
    "}\n");

var fscript = gw.makeDebuggeeValue(g.f).script;
var handler = {hit: function (frame) { g.s += '1'; }};
for (var pc of fscript.getLineOffsets(fscript.startLine + 2))
    fscript.setBreakpoint(pc, handler);

g.f();

assertEq(g.s, "a1b");

vs

var g = newGlobal();

g.s = '';

var dbg = new Debugger();

var gw = dbg.addDebuggee(g);

g.evaluate("function f() {\n" + "    s += 'a';\n" + "    s += 'b';\n" + "}\n");

var fscript = gw.makeDebuggeeValue(g.f).script;

var handler = ({
    hit: (function(frame) {
        g.s += '1';
    }),
});

for (pc of fscript.getLineOffsets(fscript.startLine + 2)) fscript.setBreakpoint(pc, handler);

g.f();

assertEq(g.s, "a1b");
// Assigning to a proxy with no set handler calls the defineProperty handler
// when an existing own data property already exists on the target.

var t = {x: 1};
var p = new Proxy(t, {
    defineProperty(t, id, desc) {
        hits++;

        // ES6 draft rev 28 (2014 Oct 14) 9.1.9 step 5.e.i.
        // Since the property already exists, the system only changes
        // the value. desc is otherwise empty.
        assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
        assertEq(desc.value, 42);
        return true;
    }
});
var hits = 0;
p.x = 42;
assertEq(hits, 1);
assertEq(t.x, 1);

vs

var t = ({
    x: 1,
});

var p = new Proxy(t, ({
    defineProperty: (function(t, id, desc) {
        hits++;
        assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
        assertEq(desc.value, 42);
        return true;
    }),
}));

var hits = 0;

p.x = 42;

assertEq(hits, 1);

assertEq(t.x, 1);
var scope = {};
scope.mod = eval(`"use strict"; (function() { "use asm"; function f() {} return f; });`);

scope.fun = scope.mod();

var caught = false;
for (let callee of ['mod', 'fun']) {
    for (let getter of ['caller', 'arguments']) {
        caught = false;
        try {
            scope[callee][getter];
        } catch (e) {
            caught = true;
            assertEq(e instanceof TypeError, true);
        }
        assertEq(caught, true);
    }
}

vs

var scope = ({});

scope.mod = eval(`"use strict"; (function() { "use asm"; function f() {} return f; });`);

scope.fun = scope.mod();

var caught = false;

for (callee of ['mod', 'fun',]) {
    for (getter of ['caller', 'arguments',]) {
        caught = false;

        try {
            scope[callee][getter];
        } catch (e) {
            caught = true;

            assertEq(e instanceof TypeError, true);
        }

        assertEq(caught, true);
    }
}
// null resumption value means terminate the debuggee

var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("(" + function () { 
        var dbg = new Debugger(debuggeeGlobal);
        dbg.onDebuggerStatement = function (frame) {
            if (frame.callee === null) {
                // The first debugger statement below.
                debuggeeGlobal.log += "1";
                var cv = frame.eval("f();");
                assertEq(cv, null);
                debuggeeGlobal.log += "2";
            } else {
                // The second debugger statement.
                debuggeeGlobal.log += "3";
                assertEq(frame.callee.name, "f");
                return null;
            }
        };
    } + ")()");

var log = "";
debugger;

function f() {
    log += "4";
    try {
        debugger;  // the debugger terminates us here
    } finally {
        log += "5";  // this should not execute
    }
}

assertEq(log, "1432");

vs

var g = newGlobal();

g.debuggeeGlobal = this;

g.eval("(" + (function() {
    var dbg = new Debugger(debuggeeGlobal);
    dbg.onDebuggerStatement = function(frame) {
        if (frame.callee === null) {
            debuggeeGlobal.log += "1";

            var cv = frame.eval("f();");

            assertEq(cv, null);

            debuggeeGlobal.log += "2";
        } else {
            debuggeeGlobal.log += "3";

            assertEq(frame.callee.name, "f");

            return null;
        }
    };
}) + ")()");

var log = "";

debugger;;

function f() {
    log += "4";
    try {
        debugger;;
    } finally {
        log += "5";
    }
}

assertEq(log, "1432");
// Forward to the target if the trap is not defined
var target = { foo: 'bar' };
for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
    assertEq(p.foo, 'bar');
    assertEq(p['foo'], 'bar');
}

var s = Symbol.for("moon");
var obj = {};
obj[s] = "dust";
for (let p of [new Proxy(obj, {}), Proxy.revocable(obj, {}).proxy])
    assertEq(p[s], "dust");

vs

var target = ({
    foo: 'bar',
});

for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy,]) {
    assertEq(p.foo, 'bar');

    assertEq(p['foo'], 'bar');
}

var s = Symbol.for("moon");

var obj = ({});

obj[s] = "dust";

for (p of [new Proxy(obj, {}), Proxy.revocable(obj, {}).proxy,]) assertEq(p[s], "dust");
// |jit-test| error: Error

var g = newGlobal();
g.eval('function f(a) { if (a == 1) debugger; evaluate("f(" + a + " - 1);"); }');
var N = 2;
var dbg = new Debugger(g);
var frames = [];
dbg.onEnterFrame = function (frame) {
   frames.push(frame);
   frame.onPop = function () { assertEq(frame.onPop, frame.onPop); };
};
dbg.onDebuggerStatement = function (frame) {
    for (var f of frames)
        f.eval('a').return;
};
evaluate("g.f(N);");

vs

var g = newGlobal();

g.eval('function f(a) { if (a == 1) debugger; evaluate("f(" + a + " - 1);"); }');

var N = 2;

var dbg = new Debugger(g);

var frames = [];

dbg.onEnterFrame = (function(frame) {
    frames.push(frame);
    frame.onPop = function() {
        assertEq(frame.onPop, frame.onPop);
    };
});

dbg.onDebuggerStatement = (function(frame) {
    for (f of frames) f.eval('a').return;
});

evaluate("g.f(N);");
// |jit-test| error: uncaught exception
g = newGlobal();
g.parent = this;
g.eval(`
    Debugger(parent).onExceptionUnwind = function(frame) { frame.older };
`);

var handler = {
    has: function(tgt, key) { if (key == 'throw') { throw null; } }
};

var proxy = new Proxy({}, handler);

for (let k of ['foo', 'throw']) {
    k in proxy;
}

vs

g = newGlobal();

g.parent = this;

g.eval(`
    Debugger(parent).onExceptionUnwind = function(frame) { frame.older };
`);

var handler = ({
    has: (function(tgt, key) {
        if (key == 'throw') {
            throw null;
        }
    }),
});

var proxy = new Proxy(({}), handler);

for (k of ['foo', 'throw',]) {
    k in proxy;
}
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap defines a non-configurable property that does
 * not exist on the target
 */
var handler = { defineProperty: function (target, name, desc) { return true; } };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy]) {
    assertThrowsInstanceOf(function () {
        Object.defineProperty(p, 'foo', { configurable: false });
    }, TypeError);
}

vs

load(libdir + "asserts.js");

var handler = ({
    defineProperty: (function(target, name, desc) {
        return true;
    }),
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) {
    assertThrowsInstanceOf(function() {
        Object.defineProperty(p, 'foo', {
            configurable: false,
        });
    }, TypeError);
}
var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
var log;
var a = [];

dbg.onDebuggerStatement = function (frame) {
  log += 'd';
  frame.onStep = function () {
    // This handler must not wipe out the debuggee's value in JSContext::iterValue.
    log += 's';
    // This will use JSContext::iterValue in the debugger.
    for (let i of a)
      log += 'i';
  };
};

log = '';
g.eval("debugger; for (let i of [1,2,3]) print(i);");
assertEq(!!log.match(/^ds*$/), true);

vs

var g = newGlobal();

var dbg = new Debugger();

var gw = dbg.addDebuggee(g);

var log;

var a = [];

dbg.onDebuggerStatement = (function(frame) {
    log += 'd';
    frame.onStep = function() {
        log += 's';
        for (i of a) log += 'i';
    };
});

log = '';

g.eval("debugger; for (let i of [1,2,3]) print(i);");

assertEq(!!log.match(/^ds*$/), true);
/*
 * Call the trap with the handler as the this value, the target as the first
 * argument, and the name of the property as the second argument
 */
var target = {};
for (var key of ['foo', Symbol('bar')]) {
    var called;
    var handler = {
        has: function (target1, name) {
            assertEq(this, handler);
            assertEq(target1, target);
            assertEq(name, key);
            called = true;
        }
    };
    for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
        called = false;
        key in p;
        assertEq(called, true);
    }
}

vs

var target = ({});

for (key of ['foo', Symbol('bar'),]) {
    var called;

    var handler = {
        has: function(target1, name) {
            assertEq(this, handler);
            assertEq(target1, target);
            assertEq(name, key);
            called = true;
        },
    };

    for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
        called = false;

        key in p;

        assertEq(called, true);
    }
}
// Binary: cache/js-dbg-64-d066929dd830-linux
// Flags: -m
//
function fnSupportsArrayIndexGettersOnObjects() {
    if (fnExists(Object.defineProperty)) {
        var obj = {};
        Object.defineProperty(obj, "0", {
            get: function () {
                supportsArrayIndexGettersOnObjects = true;
            }
        });
        var res = obj[0];
    }
    return supportsArrayIndexGettersOnObjects;
}
function fnExists( /*arguments*/ ) {
    return true;
}
var ES5Harness = (function () {
    var $this = this;
    function registerTest(test) {
        if (!(test.precondition && !test.precondition())) {
            try {
                var res = test.test.call($this);
            } catch (e) {}
        }
    }
    return {
        registerTest: registerTest
    }
})();
ES5Harness.registerTest({
    test: function testcase() {
        function callbackfn(accum, val, idx, obj) {
            if (idx === 1 && val === 1) {}
        }
        var obj = {
            length: 10
        };
        Object.defineProperty(obj, "0", {
            get: function () {
                defineProperty(idx, idx, registerTest + ": }}}}}");
            },
        });
        try {
            Array.prototype.reduce.call(obj, callbackfn, "initialValue");
        } finally {}
    },
    precondition: function prereq() {
        return fnExists(Array.prototype.reduce) && fnExists(Object.defineProperty) && fnSupportsArrayIndexGettersOnObjects();
    }
});
ES5Harness.registerTest({
    test: function testcase() {
        var obj = {};
        Object.defineProperty(obj, "property", {
            configurable: new Date()
        });
    },
    precondition: function prereq() {
        return fnExists(gczeal(2));
    }
});

vs

function fnSupportsArrayIndexGettersOnObjects() {
    if (fnExists(Object.defineProperty)) {
        var obj = {        };

        Object.defineProperty(obj, "0", {
            get: function() {
                supportsArrayIndexGettersOnObjects = true;
            },
        });

        var res = obj[0];
    }
    return supportsArrayIndexGettersOnObjects;
}

function fnExists() {
    return true;
}

var ES5Harness = (function() {
    var $this = this;
    function registerTest(test) {
        if (!test.precondition && !test.precondition()) {
            try {
                var res = test.test.call($this);
            } catch (e) { 
                
            }
        }
    }
    return {
        registerTest: registerTest,
    };
})();

ES5Harness.registerTest(({
    test: (function testcase() {
        function callbackfn(accum, val, idx, obj) {
            if (idx === 1 && val === 1) { 
                
            }
        }
        var obj = {
            length: 10,
        };
        Object.defineProperty(obj, "0", {
            get: function() {
                defineProperty(idx, idx, registerTest + ": }}}}}");
            },
        });
        try {
            Array.prototype.reduce.call(obj, callbackfn, "initialValue");
        } finally { 
            
        }
    }),
    precondition: (function prereq() {
        return fnExists(Array.prototype.reduce) && fnExists(Object.defineProperty) && fnSupportsArrayIndexGettersOnObjects();
    }),
}));

ES5Harness.registerTest(({
    test: (function testcase() {
        var obj = {        };
        Object.defineProperty(obj, "property", {
            configurable: new Date(),
        });
    }),
    precondition: (function prereq() {
        return fnExists(gczeal(2));
    }),
}));
// Binary: cache/js-dbg-64-023cb4350567-linux
// Flags:
//
uneval((function(){([z] = []).y >>= x}));

vs

uneval((function() {
    [z,] = [].y >>= x;
}));
// |jit-test| --ion-pgo=off;

// This script check that when we enable / disable the code coverage collection,
// then we have different results for the getOffsetsCoverage methods.

var g = newGlobal();
var dbg = Debugger(g);
var coverageInfo = [];
var num = 20;
function loop(i) {
  var n = 0;
  for (n = 0; n < i; n++)
    debugger;
}
g.eval(loop.toSource());

dbg.onDebuggerStatement = function (f) {
  // Collect coverage info each time we hit a debugger statement.
  coverageInfo.push(f.callee.script.getOffsetsCoverage());
};

coverageInfo = [];
dbg.collectCoverageInfo = false;
g.eval("loop(" + num + ");");
assertEq(coverageInfo.length, num);
assertEq(coverageInfo[0], null);
assertEq(coverageInfo[num - 1], null);

coverageInfo = [];
dbg.collectCoverageInfo = true;
g.eval("loop(" + num + ");");
assertEq(coverageInfo.length, num);
assertEq(!coverageInfo[0], false);
assertEq(!coverageInfo[num - 1], false);

coverageInfo = [];
dbg.collectCoverageInfo = false;
g.eval("loop(" + num + ");");
assertEq(coverageInfo.length, num);
assertEq(coverageInfo[0], null);
assertEq(coverageInfo[num - 1], null);

vs

var g = newGlobal();

var dbg = Debugger(g);

var coverageInfo = [];

var num = 20;

function loop(i) {
    var n = 0;
    for (n = 0;n < i;n++) debugger;;
}

g.eval(loop.toSource());

dbg.onDebuggerStatement = (function(f) {
    coverageInfo.push(f.callee.script.getOffsetsCoverage());
});

coverageInfo = [];

dbg.collectCoverageInfo = false;

g.eval("loop(" + num + ");");

assertEq(coverageInfo.length, num);

assertEq(coverageInfo[0], null);

assertEq(coverageInfo[num - 1], null);

coverageInfo = [];

dbg.collectCoverageInfo = true;

g.eval("loop(" + num + ");");

assertEq(coverageInfo.length, num);

assertEq(!coverageInfo[0], false);

assertEq(!coverageInfo[num - 1], false);

coverageInfo = [];

dbg.collectCoverageInfo = false;

g.eval("loop(" + num + ");");

assertEq(coverageInfo.length, num);

assertEq(coverageInfo[0], null);

assertEq(coverageInfo[num - 1], null);
// Bug 1133085 - Test that descriptors are properly reconstituted
// when only .get or only .set is present.

load(libdir + "asserts.js");

var input, output;
var p = new Proxy({x: 0}, {
    defineProperty(t, k, desc) { output = desc; print("ok"); return true; }
});

input = {get: function () {}};
Object.defineProperty(p, "x", input);
assertDeepEq(output, input);

input = {set: function () {}};
Object.defineProperty(p, "x", input);
assertDeepEq(output, input);

vs

load(libdir + "asserts.js");

var input, output;

var p = new Proxy(({
    x: 0,
}), ({
    defineProperty: (function(t, k, desc) {
        output = desc;
        print("ok");
        return true;
    }),
}));

input = ({
    get: (function() { }),
});

Object.defineProperty(p, "x", input);

assertDeepEq(output, input);

input = ({
    set: (function() { }),
});

Object.defineProperty(p, "x", input);

assertDeepEq(output, input);
var x;
-(x === null);

vs

var x;

-x === null;
// env.names() on object environments ignores property names that are not identifiers.

var g = newGlobal();
var dbg = Debugger(g);
var withNames, globalNames;
g.h = function () {
    var env = dbg.getNewestFrame().environment;
    withNames = env.names();
    while (env.parent !== null)
        env = env.parent;
    globalNames = env.names();
};

g.eval("" +
       function fill(obj) {
           obj.sanityCheck = 1;
           obj["0xcafe"] = 2;
           obj[" "] = 3;
           obj[""] = 4;
           obj[0] = 5;
           obj[Symbol.for("moon")] = 6;
           return obj;
       })
g.eval("fill(this);\n" +
       "with (fill({})) h();");

for (var names of [withNames, globalNames]) {
    assertEq(names.indexOf("sanityCheck") !== -1, true);
    assertEq(names.indexOf("0xcafe"), -1);
    assertEq(names.indexOf(" "), -1);
    assertEq(names.indexOf(""), -1);
    assertEq(names.indexOf("0"), -1);
    assertEq(names.indexOf(Symbol.for("moon")), -1);
}

vs

var g = newGlobal();

var dbg = Debugger(g);

var withNames, globalNames;

g.h = (function() {
    var env = dbg.getNewestFrame().environment;
    withNames = env.names();
    while (env.parent !== null) env = env.parent;
    globalNames = env.names();
});

g.eval("" + (function fill(obj) {
    obj.sanityCheck = 1;
    obj["0xcafe"] = 2;
    obj[" "] = 3;
    obj[""] = 4;
    obj[0] = 5;
    obj[Symbol.for("moon")] = 6;
    return obj;
}));

g.eval("fill(this);\n" + "with (fill({})) h();");

for (names of [withNames, globalNames,]) {
    assertEq(names.indexOf("sanityCheck") !== -1, true);

    assertEq(names.indexOf("0xcafe"), -1);

    assertEq(names.indexOf(" "), -1);

    assertEq(names.indexOf(""), -1);

    assertEq(names.indexOf("0"), -1);

    assertEq(names.indexOf(Symbol.for("moon")), -1);
}
load(libdir + "asserts.js");

// Throw a TypeError if the trap sets a non-writable, non-configurable property
for (var key of ['foo', Symbol.for('quux')]) {
    var target = {};
    Object.defineProperty(target, key, {
        value: 'bar',
        writable: false,
        configurable: false
    });
    var handler = { set: () => true };
    for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
        assertThrowsInstanceOf(() => p[key] = 'baz', TypeError);
}

vs

load(libdir + "asserts.js");

for (key of ['foo', Symbol.for('quux'),]) {
    var target = {    };

    Object.defineProperty(target, key, {
        value: 'bar',
        writable: false,
        configurable: false,
    });

    var handler = {
        set: ()  => true,
    };

    for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => p[key] = 'baz', TypeError);
}
// Check that {return:} resumption kills the current stack frame.

var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("(" + function () {
        var dbg = new Debugger(debuggeeGlobal);
        var prev = null;
        dbg.onDebuggerStatement = function (frame) {
            assertEq(frame === prev, false);
            if (prev)
                assertEq(prev.live, false);
            prev = frame;
            return {return: frame.arguments[0]};
        };
    } + ")();");

function f(i) { debugger; }
for (var i = 0; i < 10; i++)
    assertEq(f(i), i);

vs

var g = newGlobal();

g.debuggeeGlobal = this;

g.eval("(" + (function() {
    var dbg = new Debugger(debuggeeGlobal);
    var prev = null;
    dbg.onDebuggerStatement = function(frame) {
        assertEq(frame === prev, false);
        if (prev) assertEq(prev.live, false);

        prev = frame;
        return {
            return: frame.arguments[0],
        };
    };
}) + ")();");

function f(i) {
    debugger;;
}

for (let i = 0;i < 10;i++) assertEq(f(i), i);
// A debugger can {throw:} from onEnterFrame at any resume point in a generator.
// It closes the generator.

load(libdir + "asserts.js");

let g = newGlobal();
g.eval(`
    function* f() { yield 1; }
    var exn = new TypeError("object too hairy");
`);

let dbg = new Debugger;
let gw = dbg.addDebuggee(g);

// Repeat the test for each onEnterFrame event.
// It fires up to three times:
// - when the generator g.f is called;
// - when we enter it to run to `yield 1`;
// - when we resume after the yield to run to the end.
for (let i = 0; i < 3; i++) {
    let hits = 0;
    dbg.onEnterFrame = frame => {
        return hits++ < i ? undefined : {throw: gw.makeDebuggeeValue(g.exn)};
    };
    let genObj;
    assertThrowsValue(
        () => {
            genObj = g.f();
            for (let x of genObj) {}
        },
        g.exn
    );
    assertEq(hits, i + 1);
    if (hits > 1)
        assertEq(genObj.next().done, true);
}

vs

load(libdir + "asserts.js");

let g = newGlobal();

g.eval(`
    function* f() { yield 1; }
    var exn = new TypeError("object too hairy");
`);

let dbg = new Debugger();

let gw = dbg.addDebuggee(g);

for (let i = 0;i < 3;i++) {
    let hits = 0;

    dbg.onEnterFrame = frame => {
        return hits++ < i ? undefined : {
            throw: gw.makeDebuggeeValue(g.exn),
        };
    };

    let genObj;

    assertThrowsValue(()  => {
        genObj = g.f();
        for (x of genObj) { 
            
        }
    }, g.exn);

    assertEq(hits, i + 1);

    if (hits > 1) assertEq(genObj.next().done, true);

}
// Async stacks should not supplant LiveSavedFrameCache hits.

top();

// An ordinary function, to give the frame a convenient name.
function top() {
  // Perform an async call. F will run in an activation that has an async stack
  // supplied.
  f().catch(catchError);
}

async function f() {
  // Perform an ordinary call. Its parent frame will be a LiveSavedFrameCache
  // hit.
  g();
}

function g() {
  // Populate the LiveSavedFrameCache.
  saveStack();

  // Capturing the stack again should find f (if not g) in the cache. The async
  // stack supplied below the call to f should not supplant f's own frame.
  let frame = saveStack();

  assertEq(frame.functionDisplayName, 'g');
  assertEq(parent(frame).functionDisplayName, 'f');
  assertEq(parent(parent(frame)).functionDisplayName, 'top');
}

// Return the parent of |frame|, skipping self-hosted code and following async
// parent links.
function parent(frame) {
  do {
    frame = frame.parent || frame.asyncParent;
  } while (frame.source.match(/self-hosted/));
  return frame;
}

function catchError(e) {
  print(`${e}\n${e.stack}`);
  quit(1)
}

vs

top();

function top() {
    f().catch(catchError);
}

(async function f() {
    g();
});

function g() {
    saveStack();
    let frame = saveStack();
    assertEq(frame.functionDisplayName, 'g');
    assertEq(parent(frame).functionDisplayName, 'f');
    assertEq(parent(parent(frame)).functionDisplayName, 'top');
}

function parent(frame) {
    do {
        frame = frame.parent || frame.asyncParent;
    } while (frame.source.match(/self-hosted/));
    ;
    return frame;
}

function catchError(e) {
    print(`${e}\n{e.stack}`);
    quit(1);
}
load(libdir + "asserts.js");

// Throw a TypeError if the trap does not return an object
var handler = { ownKeys: () => undefined };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    ownKeys: ()  => undefined,
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyNames(p), TypeError);
// |jit-test| skip-if: !wasmDebuggingIsSupported()

// Tests that wasm module scripts are available via findScripts.

var g = newGlobal();
g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);

function isWasm(script) { return script.format === "wasm"; }

var dbg = new Debugger(g);
var foundScripts1 = dbg.findScripts().filter(isWasm);
assertEq(foundScripts1.length, 1);
var found = foundScripts1[0];

// Add another module, we should be able to find it via findScripts.
g.eval(`o2 = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "a" 0))')));`);
var foundScripts2 = dbg.findScripts().filter(isWasm);
assertEq(foundScripts2.length, 2);

// The first module should be in the list as wrapping the same wasm module
// twice gets the same Debugger.Script.
assertEq(foundScripts2.indexOf(found) !== -1, true);

// The two modules are distinct.
assertEq(foundScripts2[0] !== foundScripts2[1], true);

// We should be able to find the same script via its source.
for (var ws of foundScripts2) {
  var scriptsFromSource = dbg.findScripts({ source: ws.source });
  assertEq(scriptsFromSource.length, 1);
  assertEq(scriptsFromSource[0], ws);
}

vs

var g = newGlobal();

g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);

function isWasm(script) {
    return script.format === "wasm";
}

var dbg = new Debugger(g);

var foundScripts1 = dbg.findScripts().filter(isWasm);

assertEq(foundScripts1.length, 1);

var found = foundScripts1[0];

g.eval(`o2 = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "a" 0))')));`);

var foundScripts2 = dbg.findScripts().filter(isWasm);

assertEq(foundScripts2.length, 2);

assertEq(foundScripts2.indexOf(found) !== -1, true);

assertEq(foundScripts2[0] !== foundScripts2[1], true);

for (ws of foundScripts2) {
    var scriptsFromSource = dbg.findScripts({
        source: ws.source,
    });

    assertEq(scriptsFromSource.length, 1);

    assertEq(scriptsFromSource[0], ws);
}
// Binary: cache/js-dbg-32-b39f4007be5a-linux
// Flags: -m -n -a
//

gczeal(4);
var a = ['a','test string',456,9.34,new String("string object"),[],['h','i','j','k']];
var b = [1,2,3,4,5,6,7,8,9,0];
exhaustiveSliceTest("exhaustive slice test 1", a);
function mySlice(a, from, to) {
  var returnArray = [];
  try {  }  catch ( [ x   ]   ) {  }   finally {  }
  return returnArray;
}
function exhaustiveSliceTest(testname, a) {
  var x = 0;
    for (y = (2 + a.length); y >= -(2 + a.length); y--) {
      var c = mySlice(a,x,y);
      if (String(b) != String(c))
          " expected result: " + String(c) + "\n";
    }
}

vs

gczeal(4);

var a = ['a', 'test string', 456, 9.34, new String("string object"), [], ['h', 'i', 'j', 'k',],];

var b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0,];

exhaustiveSliceTest("exhaustive slice test 1", a);

function mySlice(a, from, to) {
    var returnArray = [];
    try { 
        
    } catch ([x,]) { 
        
    } finally { 
        
    }
    return returnArray;
}

function exhaustiveSliceTest(testname, a) {
    var x = 0;
    for (y = 2 + a.length;y >= -2 + a.length;y--) {
        var c = mySlice(a, x, y);

        if (String(b) != String(c)) " expected result: " + String(c) + "\n";

    }
}
load(libdir + 'asserts.js');

function test() {
  let a = ctypes.int32_t.array(10)();
  assertTypeErrorMessage(() => { let x = a[-1]; },
                          "the string \"-1\" is not a valid array index");
  assertTypeErrorMessage(() => { a[-1] = 1; },
                          "the string \"-1\" is not a valid array index");
  assertTypeErrorMessage(() => { a.addressOfElement(-1); },
                          "the number -1 is not a valid array index");

  assertRangeErrorMessage(() => { let x = a[10]; },
                          "array index 10 is out of bounds for array of length 10");
  assertRangeErrorMessage(() => { a[10] = 1; },
                          "array index 10 is out of bounds for array of length 10");
  assertRangeErrorMessage(() => { a.addressOfElement(10); },
                          "array index 10 is out of bounds for array of length 10");

  let obj = {
    toSource() {
      throw 1;
    }
  };
  assertTypeErrorMessage(() => { a.addressOfElement(obj); },
                          "<<error converting value to string>> is not a valid array index");
}

if (typeof ctypes === "object")
  test();

vs

load(libdir + 'asserts.js');

function test() {
    let a = ctypes.int32_t.array(10)();
    assertTypeErrorMessage(()  => {
        let x = a[-1];
    }, "the string \"-1\" is not a valid array index");
    assertTypeErrorMessage(()  => {
        a[-1] = 1;
    }, "the string \"-1\" is not a valid array index");
    assertTypeErrorMessage(()  => {
        a.addressOfElement(-1);
    }, "the number -1 is not a valid array index");
    assertRangeErrorMessage(()  => {
        let x = a[10];
    }, "array index 10 is out of bounds for array of length 10");
    assertRangeErrorMessage(()  => {
        a[10] = 1;
    }, "array index 10 is out of bounds for array of length 10");
    assertRangeErrorMessage(()  => {
        a.addressOfElement(10);
    }, "array index 10 is out of bounds for array of length 10");
    let obj = {
        toSource: function() {
            throw 1;
        },
    };
    assertTypeErrorMessage(()  => {
        a.addressOfElement(obj);
    }, "<<error converting value to string>> is not a valid array index");
}

if (typeof ctypes === "object") test();

load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap sets a non-configurable accessor property that
 * doest not have a setter
 */
var target = {};
Object.defineProperty(target, 'foo', {
    get: function () {
        return 'bar'
    },
    configurable: false
});

var handler = { set: () => true };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => p['foo'] = 'baz', TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    get: (function() {
        return 'bar';
    }),
    configurable: false,
}));

var handler = ({
    set: ()  => true,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => p['foo'] = 'baz', TypeError);
// Test AutoSetAsyncStackForNewCalls's IMPLICIT kind.

// Given a SavedFrame stack, return a string listing the frame's function names
// and their async causes, if any.
function stackFunctions(stack) {
  const frames = [];
  for (; stack; stack = stack.parent || stack.asyncParent) {
    if (!stack.functionDisplayName) {
      frames.push('(top level)');
    } else if (stack.asyncCause) {
      frames.push(`${stack.asyncCause}*${stack.functionDisplayName}`);
    } else {
      frames.push(stack.functionDisplayName);
    }
  }
  return frames.join(', ');
}

let fakeStack = (function fake1() {
  function fake2() {
    return saveStack();
  }
  return fake2();
})();

function bindAndExpect(options, expected) {
  function bindee() {
    assertEq(stackFunctions(saveStack()), expected);
  }

  return bindToAsyncStack(bindee, options);
}

function caller(f) {
  return f();
}

// An explicit async stack always overrides the actual callers of the bindee.
// An implicit async stack never overrides callers; it is only attached when
// the stack is otherwise empty.
caller(bindAndExpect({ stack: fakeStack, cause: 'ano', explicit: false },
                     "bindee, caller, (top level)"));

caller(bindAndExpect({ stack: fakeStack, cause: 'hi', explicit: true },
                     "bindee, hi*fake2, fake1, (top level)"));

enqueueJob(bindAndExpect({ stack: fakeStack, cause: 'mita', explicit: false },
                         "bindee, mita*fake2, fake1, (top level)"));

enqueueJob(bindAndExpect({ stack: fakeStack, cause: 'hana', explicit: true },
                         "bindee, hana*fake2, fake1, (top level)"));

vs

function stackFunctions(stack) {
    const frames = [];
    for (;stack;stack = stack.parent || stack.asyncParent) {
        if (!stack.functionDisplayName) {
            frames.push('(top level)');
        } else if (stack.asyncCause) {
            frames.push(`${stack.asyncCause}*{stack.functionDisplayName}`);
        } else {
            frames.push(stack.functionDisplayName);
        }

    }
    return frames.join(', ');
}

let fakeStack = (function fake1() {
    function fake2() {
        return saveStack();
    }
    return fake2();
})();

function bindAndExpect(options, expected) {
    function bindee() {
        assertEq(stackFunctions(saveStack()), expected);
    }
    return bindToAsyncStack(bindee, options);
}

function caller(f) {
    return f();
}

caller(bindAndExpect(({
    stack: fakeStack,
    cause: 'ano',
    explicit: false,
}), "bindee, caller, (top level)"));

caller(bindAndExpect(({
    stack: fakeStack,
    cause: 'hi',
    explicit: true,
}), "bindee, hi*fake2, fake1, (top level)"));

enqueueJob(bindAndExpect(({
    stack: fakeStack,
    cause: 'mita',
    explicit: false,
}), "bindee, mita*fake2, fake1, (top level)"));

enqueueJob(bindAndExpect(({
    stack: fakeStack,
    cause: 'hana',
    explicit: true,
}), "bindee, hana*fake2, fake1, (top level)"));
// Assigning to a non-existing property of a plain object defines that
// property on that object, even if a proxy is on the proto chain.

// Create an object that behaves just like obj except it throws (instead of
// returning undefined) if you try to get a property that doesn't exist.
function throwIfNoSuchProperty(obj) {
    return new Proxy(obj, {
        get(t, id) {
            if (id in t)
                return t[id];
            throw new Error("no such handler method: " + id);
        }
    });
}

// Use a touchy object as our proxy handler in this test.
var hits = 0, savedDesc = undefined;
var touchyHandler = throwIfNoSuchProperty({
    set: undefined
});
var target = {};
var proto = new Proxy(target, touchyHandler);
var receiver = Object.create(proto);

// This assignment `receiver.x = 2` results in a series of [[Set]] calls,
// starting with:
//
// - receiver.[[Set]]()
//     - receiver is an ordinary object.
//     - This looks for an own property "x" on receiver. There is none.
//     - So it walks the prototype chain, doing a tail-call to:
// - proto.[[Set]]()
//     - proto is a proxy.
//     - This does handler.[[Get]]("set") to look for a set trap
//         (that's why we need `set: undefined` on the handler, above)
//     - Since there's no "set" handler, it tail-calls:
// - target.[[Set]]()
//     - ordinary
//     - no own property "x"
//     - tail call to:
// - Object.prototype.[[Set]]()
//     - ordinary
//     - no own property "x"
//     - We're at the end of the line: there's nothing left on the proto chain.
//     - So at last we call:
// - receiver.[[DefineOwnProperty]]()
//     - ordinary
//     - creates the property
//
// Got all that? Let's try it.
//
receiver.x = 2;
assertEq(receiver.x, 2);

var desc = Object.getOwnPropertyDescriptor(receiver, "x");
assertEq(desc.enumerable, true);
assertEq(desc.configurable, true);
assertEq(desc.writable, true);
assertEq(desc.value, 2);

vs

function throwIfNoSuchProperty(obj) {
    return new Proxy(obj, {
        get: function(t, id) {
            if (id in t) return t[id];

            throw new Error("no such handler method: " + id);
        },
    });
}

var hits = 0, savedDesc = undefined;

var touchyHandler = throwIfNoSuchProperty(({
    set: undefined,
}));

var target = ({});

var proto = new Proxy(target, touchyHandler);

var receiver = Object.create(proto);

receiver.x = 2;

assertEq(receiver.x, 2);

var desc = Object.getOwnPropertyDescriptor(receiver, "x");

assertEq(desc.enumerable, true);

assertEq(desc.configurable, true);

assertEq(desc.writable, true);

assertEq(desc.value, 2);
// |jit-test| error: TypeError
new DoWhileObject;
function DoWhileObject(breakOut, breakIn, iterations, loops) {
    loops.prototype = new DoWhile;
    this.looping;
}
function DoWhile(object) {
    do {} while (object);
}

vs

new DoWhileObject();

function DoWhileObject(breakOut, breakIn, iterations, loops) {
    loops.prototype = new DoWhile();
    this.looping;
}

function DoWhile(object) {
    do { 
        
    } while (object);
    ;
}
// only fix doubles for slots which the recompiled script thinks are doubles.
function foo(x) {
  var y = x & 0xffff;
  y = (y * (x * 1000));
  assertEq(y, 140735340806145000);
}
foo(0x7fffffff);

vs

function foo(x) {
    var y = x & 0xffff;
    y = y * x * 1000;
    assertEq(y, 140735340806145000);
}

foo(0x7fffffff);
// |jit-test| test-also-no-wasm-baseline; skip-if: !wasmDebuggingIsSupported()

// Tests that wasm module sourceMappingURL section is parsed.

load(libdir + "asserts.js");
load(libdir + "wasm-binary.js");

var g = newGlobal();
var dbg = new Debugger(g);

var gotScript;
dbg.allowWasmBinarySource = true;
dbg.onNewScript = (script) => {
  gotScript = script;
}

function toU8(array) {
    for (let b of array)
        assertEq(b < 256, true);
    return Uint8Array.from(array);
}

function varU32(u32) {
    assertEq(u32 >= 0, true);
    assertEq(u32 < Math.pow(2,32), true);
    var bytes = [];
    do {
        var byte = u32 & 0x7f;
        u32 >>>= 7;
        if (u32 != 0)
            byte |= 0x80;
        bytes.push(byte);
    } while (u32 != 0);
    return bytes;
}

function string(name) {
    var nameBytes = name.split('').map(c => {
        var code = c.charCodeAt(0);
        assertEq(code < 128, true); // TODO
        return code;
    });
    return varU32(nameBytes.length).concat(nameBytes);
}

function appendSourceMappingURL(wasmBytes, url) {
    if (!url)
        return wasmBytes;
    var payload = [...string('sourceMappingURL'), ...string(url)];
    return Uint8Array.from([...wasmBytes, userDefinedId, payload.length, ...payload]);
}
g.toWasm = (wast, url) => appendSourceMappingURL(wasmTextToBinary(wast), url);

// The sourceMappingURL section is not present
g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(toWasm('(module (func) (export "" 0))')));`);
assertEq(gotScript.format, "wasm");
assertEq(gotScript.source.sourceMapURL, null);

// The sourceMappingURL section is present
g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(toWasm('(module (func) (export "a" 0))', 'http://example.org/test')));`);
assertEq(gotScript.format, "wasm");
assertEq(gotScript.source.sourceMapURL, 'http://example.org/test');

// The sourceMapURL is read-only for wasm
assertThrowsInstanceOf(() => gotScript.source.sourceMapURL = 'foo', Error);

// The sourceMappingURL section is present, and is still available when wasm
// binary source is disabled.
dbg.allowWasmBinarySource = false;
g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(toWasm('(module (func) (export "a" 0))', 'http://example.org/test2')));`);
assertEq(gotScript.format, "wasm");
assertEq(gotScript.source.sourceMapURL, 'http://example.org/test2');

vs

load(libdir + "asserts.js");

load(libdir + "wasm-binary.js");

var g = newGlobal();

var dbg = new Debugger(g);

var gotScript;

dbg.allowWasmBinarySource = true;

dbg.onNewScript = script => {
    gotScript = script;
};

function toU8(array) {
    for (b of array) assertEq(b < 256, true);
    return Uint8Array.from(array);
}

function varU32(u32) {
    assertEq(u32 >= 0, true);
    assertEq(u32 < Math.pow(2, 32), true);
    var bytes = [];
    do {
        var byte = u32 & 0x7f;

        u32 >>>= 7;

        if (u32 != 0) byte |= 0x80;


        bytes.push(byte);
    } while (u32 != 0);
    ;
    return bytes;
}

function string(name) {
    var nameBytes = name.split('').map(c => {
        var code = c.charCodeAt(0);
        assertEq(code < 128, true);
        return code;
    });
    return varU32(nameBytes.length).concat(nameBytes);
}

function appendSourceMappingURL(wasmBytes, url) {
    if (!url) return wasmBytes;

    var payload = [...string('sourceMappingURL'), ...string(url),];
    return Uint8Array.from([...wasmBytes, userDefinedId, payload.length, ...payload,]);
}

g.toWasm = (wast, url)  => appendSourceMappingURL(wasmTextToBinary(wast), url);

g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(toWasm('(module (func) (export "" 0))')));`);

assertEq(gotScript.format, "wasm");

assertEq(gotScript.source.sourceMapURL, null);

g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(toWasm('(module (func) (export "a" 0))', 'http://example.org/test')));`);

assertEq(gotScript.format, "wasm");

assertEq(gotScript.source.sourceMapURL, 'http://example.org/test');

assertThrowsInstanceOf(()  => gotScript.source.sourceMapURL = 'foo', Error);

dbg.allowWasmBinarySource = false;

g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(toWasm('(module (func) (export "a" 0))', 'http://example.org/test2')));`);

assertEq(gotScript.format, "wasm");

assertEq(gotScript.source.sourceMapURL, 'http://example.org/test2');
// Cull non-existent names returned by the trap.
var nullProtoAB = Object.create(null, {
    a: {
        enumerable: true,
        configurable: true
    },
    b: {
        enumerable: false,
        configurable: true
    }
});
var protoABWithCD = Object.create(nullProtoAB, {
    c: {
        enumerable: true,
        configurable: true
    },
    d: {
        enumerable: false,
        configurable: true
    }
});

var returnedNames;
var handler = { ownKeys: () => returnedNames };

for (let p of [new Proxy(protoABWithCD, handler), Proxy.revocable(protoABWithCD, handler).proxy]) {
    returnedNames = [ 'e' ];
    var names = Object.keys(p);
    assertEq(names.length, 0);

    returnedNames = [ 'c' ];
    names = Object.keys(p);
    assertEq(names.length, 1);
    assertEq(names[0], 'c');
}

vs

var nullProtoAB = Object.create(null, ({
    a: ({
        enumerable: true,
        configurable: true,
    }),
    b: ({
        enumerable: false,
        configurable: true,
    }),
}));

var protoABWithCD = Object.create(nullProtoAB, ({
    c: ({
        enumerable: true,
        configurable: true,
    }),
    d: ({
        enumerable: false,
        configurable: true,
    }),
}));

var returnedNames;

var handler = ({
    ownKeys: ()  => returnedNames,
});

for (p of [new Proxy(protoABWithCD, handler), Proxy.revocable(protoABWithCD, handler).proxy,]) {
    returnedNames = ['e',];

    var names = Object.keys(p);

    assertEq(names.length, 0);

    returnedNames = ['c',];

    names = Object.keys(p);

    assertEq(names.length, 1);

    assertEq(names[0], 'c');
}
// Basic functional tests for the Atomics primitives.
//
// These do not test atomicity, just that calling and coercions and
// indexing and exception behavior all work right.
//
// These do not test the wait/wake operations.

load(libdir + "asserts.js");

var DEBUG = false;		// Set to true for useful printouts

function dprint(...xs) {
    if (!DEBUG)
	return;
    var s = "";
    for ( var x in xs )
	s += String(xs[x]);
    print(s);
}

// Clone a function so that we get reliable inlining of primitives with --ion-eager.
// For eg testMethod and testFunction that are polymorphic in the array a,
// the inliner gets confused and stops inlining after Int8 -- not what we want.
function CLONE(f) {
    return this.eval("(" + f.toSource() + ")");
}

function testMethod(a, ...indices) {
    dprint("Method: " + a.constructor.name);
    var poison;
    switch (a.BYTES_PER_ELEMENT) {
    case 1: poison = 0x5A; break;
    case 2: poison = 0x5A5A; break;
    case 4: poison = 0x5A5A5A5A; break;
    }
    for ( var i=0 ; i < indices.length ; i++ ) {
	var x = indices[i];
	if (x > 0)
	    a[x-1] = poison;
	if (x < a.length-1)
	    a[x+1] = poison;

	// val = 0
	assertEq(Atomics.compareExchange(a, x, 0, 37), 0);
	// val = 37
	assertEq(Atomics.compareExchange(a, x, 37, 5), 37);
	// val = 5
	assertEq(Atomics.compareExchange(a, x, 7, 8), 5); // ie should fail
	// val = 5
	assertEq(Atomics.compareExchange(a, x, 5, 9), 5);
	// val = 9
	assertEq(Atomics.compareExchange(a, x, 5, 0), 9); // should also fail

 	// val = 9
	assertEq(Atomics.exchange(a, x, 4), 9);
	// val = 4
	assertEq(Atomics.exchange(a, x, 9), 4);

	// val = 9
	assertEq(Atomics.load(a, x), 9);
	// val = 9
	assertEq(Atomics.store(a, x, 14), 14); // What about coercion?
	// val = 14
	assertEq(Atomics.load(a, x), 14);
	// val = 14
	Atomics.store(a, x, 0);
	// val = 0

	// val = 0
	assertEq(Atomics.add(a, x, 3), 0);
	// val = 3
	assertEq(Atomics.sub(a, x, 2), 3);
	// val = 1
	assertEq(Atomics.or(a, x, 6), 1);
	// val = 7
	assertEq(Atomics.and(a, x, 14), 7);
	// val = 6
	assertEq(Atomics.xor(a, x, 5), 6);
	// val = 3
	assertEq(Atomics.load(a, x), 3);
	// val = 3
	Atomics.store(a, x, 0);
	// val = 0

	// Check adjacent elements were not affected
	if (x > 0) {
	    assertEq(a[x-1], poison);
	    a[x-1] = 0;
	}
	if (x < a.length-1) {
	    assertEq(a[x+1], poison);
	    a[x+1] = 0;
	}
    }
}

function testFunction(a, ...indices) {
    dprint("Function: " + a.constructor.name);
    var poison;
    switch (a.BYTES_PER_ELEMENT) {
    case 1: poison = 0x5A; break;
    case 2: poison = 0x5A5A; break;
    case 4: poison = 0x5A5A5A5A; break;
    }
    for ( var i=0 ; i < indices.length ; i++ ) {
	var x = indices[i];
	if (x > 0)
	    a[x-1] = poison;
	if (x < a.length-1)
	    a[x+1] = poison;

	// val = 0
	assertEq(gAtomics_compareExchange(a, x, 0, 37), 0);
	// val = 37
	assertEq(gAtomics_compareExchange(a, x, 37, 5), 37);
	// val = 5
	assertEq(gAtomics_compareExchange(a, x, 7, 8), 5); // ie should fail
	// val = 5
	assertEq(gAtomics_compareExchange(a, x, 5, 9), 5);
	// val = 9
	assertEq(gAtomics_compareExchange(a, x, 5, 0), 9); // should also fail

	// val = 9
	assertEq(gAtomics_exchange(a, x, 4), 9);
	// val = 4
	assertEq(gAtomics_exchange(a, x, 9), 4);

	// val = 9
	assertEq(gAtomics_load(a, x), 9);
	// val = 9
	assertEq(gAtomics_store(a, x, 14), 14); // What about coercion?
	// val = 14
	assertEq(gAtomics_load(a, x), 14);
	// val = 14
	gAtomics_store(a, x, 0);
	// val = 0

	// val = 0
	assertEq(gAtomics_add(a, x, 3), 0);
	// val = 3
	assertEq(gAtomics_sub(a, x, 2), 3);
	// val = 1
	assertEq(gAtomics_or(a, x, 6), 1);
	// val = 7
	assertEq(gAtomics_and(a, x, 14), 7);
	// val = 6
	assertEq(gAtomics_xor(a, x, 5), 6);
	// val = 3
	assertEq(gAtomics_load(a, x), 3);
	// val = 3
	gAtomics_store(a, x, 0);
	// val = 0

	// Check adjacent elements were not affected
	if (x > 0) {
	    assertEq(a[x-1], poison);
	    a[x-1] = 0;
	}
	if (x < a.length-1) {
	    assertEq(a[x+1], poison);
	    a[x+1] = 0;
	}
    }
}

function testTypeCAS(a) {
    dprint("Type: " + a.constructor.name);

    var thrown = false;
    try {
	Atomics.compareExchange([0], 0, 0, 1);
    }
    catch (e) {
	thrown = true;
	assertEq(e instanceof TypeError, true);
    }
    assertEq(thrown, true);

    // All these variants should be OK
    Atomics.compareExchange(a, 0, 0.7, 1.8);
    Atomics.compareExchange(a, 0, "0", 1);
    Atomics.compareExchange(a, 0, 0, "1");
    Atomics.compareExchange(a, 0, 0);
}

function testTypeBinop(a, op) {
    dprint("Type: " + a.constructor.name);

    var thrown = false;
    try {
	op([0], 0, 1);
    }
    catch (e) {
	thrown = true;
	assertEq(e instanceof TypeError, true);
    }
    assertEq(thrown, true);

    // These are all OK
    op(a, 0, 0.7);
    op(a, 0, "0");
    op(a, 0);
}

var globlength = 0;		// Will be set later

function testRangeCAS(a) {
    dprint("Range: " + a.constructor.name);

    var msg = /out-of-range index/; // A generic message

    assertErrorMessage(() => Atomics.compareExchange(a, -1, 0, 1), RangeError, msg);
    assertEq(a[0], 0);

    // Converted to 0
    assertEq(Atomics.compareExchange(a, "hi", 0, 33), 0);
    assertEq(a[0], 33);
    a[0] = 0;

    assertErrorMessage(() => Atomics.compareExchange(a, a.length + 5, 0, 1), RangeError, msg);
    assertEq(a[0], 0);

    assertErrorMessage(() => Atomics.compareExchange(a, globlength, 0, 1), RangeError, msg);
    assertEq(a[0], 0);
}

// Ad-hoc tests for extreme and out-of-range values.
// None of these should throw

function testInt8Extremes(a) {
    dprint("Int8 extremes");

    a[10] = 0;
    a[11] = 0;

    Atomics.store(a, 10, 255);
    assertEq(a[10], -1);
    assertEq(Atomics.load(a, 10), -1);

    Atomics.add(a, 10, 255); // should coerce to -1
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.add(a, 10, -1);
    assertEq(a[10], -3);
    assertEq(Atomics.load(a, 10), -3);

    Atomics.sub(a, 10, 255);	// should coerce to -1
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.sub(a, 10, 256);	// should coerce to 0
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.and(a, 10, -1);	// Preserve all
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.and(a, 10, 256);	// Preserve none
    assertEq(a[10], 0);
    assertEq(Atomics.load(a, 10), 0);

    Atomics.store(a, 10, 255);
    assertEq(Atomics.exchange(a, 10, 0), -1);

    assertEq(a[11], 0);
}

function testUint8Extremes(a) {
    dprint("Uint8 extremes");

    a[10] = 0;
    a[11] = 0;

    Atomics.store(a, 10, 255);
    assertEq(a[10], 255);
    assertEq(Atomics.load(a, 10), 255);

    Atomics.add(a, 10, 255);
    assertEq(a[10], 254);
    assertEq(Atomics.load(a, 10), 254);

    Atomics.add(a, 10, -1);
    assertEq(a[10], 253);
    assertEq(Atomics.load(a, 10), 253);

    Atomics.sub(a, 10, 255);
    assertEq(a[10], 254);
    assertEq(Atomics.load(a, 10), 254);

    Atomics.and(a, 10, -1);	// Preserve all
    assertEq(a[10], 254);
    assertEq(Atomics.load(a, 10), 254);

    Atomics.and(a, 10, 256);	// Preserve none
    assertEq(a[10], 0);
    assertEq(Atomics.load(a, 10), 0);

    Atomics.store(a, 10, 255);
    assertEq(Atomics.exchange(a, 10, 0), 255);

    assertEq(a[11], 0);
}

function testInt16Extremes(a) {
    dprint("Int16 extremes");

    a[10] = 0;
    a[11] = 0;

    Atomics.store(a, 10, 65535);
    assertEq(a[10], -1);
    assertEq(Atomics.load(a, 10), -1);

    Atomics.add(a, 10, 65535); // should coerce to -1
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.add(a, 10, -1);
    assertEq(a[10], -3);
    assertEq(Atomics.load(a, 10), -3);

    Atomics.sub(a, 10, 65535);	// should coerce to -1
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.sub(a, 10, 65536);	// should coerce to 0
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.and(a, 10, -1);	// Preserve all
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);

    Atomics.and(a, 10, 65536);	// Preserve none
    assertEq(a[10], 0);
    assertEq(Atomics.load(a, 10), 0);

    assertEq(a[11], 0);
}

function testUint32(a) {
    var k = 0;
    for ( var i=0 ; i < 20 ; i++ ) {
	a[i] = i+5;
	k += a[i];
    }

    var sum = 0;
    for ( var i=0 ; i < 20 ; i++ )
	sum += Atomics.add(a, i, 1);

    assertEq(sum, k);
}

// This test is a reliable test of sign extension in the JIT where
// testInt8Extremes is not (because there may not be enough type
// information without a loop - see bug 1181062 for a description
// of the general problem).

function exchangeLoop(ta) {
    var sum = 0;
    for ( var i=0 ; i < 100000 ; i++ )
	sum += Atomics.exchange(ta, i & 15, 255);
    return sum;
}

function adHocExchange() {
    var a = new Int8Array(new SharedArrayBuffer(16));
    for ( var i=0 ; i < a.length ; i++ )
	a[i] = 255;
    assertEq(exchangeLoop(a), -100000);
}

// isLockFree(n) may return true only if there is an integer array
// on which atomic operations is allowed whose byte size is n,
// ie, it must return false for n=8.
//
// SpiderMonkey has isLockFree(1), isLockFree(2), isLockFree(4) on all
// supported platforms, only the last is guaranteed by the spec.

var sizes   = [    1,     2,     3,     4,     5,     6,     7,  8,
                   9,    10,    11,    12];
var answers = [ true,  true, false,  true, false, false, false, false,
	       false, false, false, false];

function testIsLockFree() {
    // This ought to defeat most compile-time resolution.
    for ( var i=0 ; i < sizes.length ; i++ ) {
	var v = Atomics.isLockFree(sizes[i]);
	var a = answers[i];
	assertEq(typeof v, 'boolean');
	assertEq(v, a);
    }

    // This ought to be optimizable.
    assertEq(Atomics.isLockFree(1), true);
    assertEq(Atomics.isLockFree(2), true);
    assertEq(Atomics.isLockFree(3), false);
    assertEq(Atomics.isLockFree(4), true);
    assertEq(Atomics.isLockFree(5), false);
    assertEq(Atomics.isLockFree(6), false);
    assertEq(Atomics.isLockFree(7), false);
    assertEq(Atomics.isLockFree(8), false);
    assertEq(Atomics.isLockFree(9), false);
    assertEq(Atomics.isLockFree(10), false);
    assertEq(Atomics.isLockFree(11), false);
    assertEq(Atomics.isLockFree(12), false);
}

function testIsLockFree2() {
    assertEq(Atomics.isLockFree(0), false);
    assertEq(Atomics.isLockFree(0/-1), false);
    assertEq(Atomics.isLockFree(3.5), false);
    assertEq(Atomics.isLockFree(Number.NaN), false);  // NaN => +0
    assertEq(Atomics.isLockFree(Number.POSITIVE_INFINITY), false);
    assertEq(Atomics.isLockFree(Number.NEGATIVE_INFINITY), false);
    assertEq(Atomics.isLockFree(-4), false);
    assertEq(Atomics.isLockFree('4'), true);
    assertEq(Atomics.isLockFree('-4'), false);
    assertEq(Atomics.isLockFree('4.5'), true);
    assertEq(Atomics.isLockFree('5.5'), false);
    assertEq(Atomics.isLockFree(new Number(4)), true);
    assertEq(Atomics.isLockFree(new String('4')), true);
    assertEq(Atomics.isLockFree(new Boolean(true)), true);
    var thrown = false;
    try {
	Atomics.isLockFree(Symbol('1'));
    } catch (e) {
	thrown = e;
    }
    assertEq(thrown instanceof TypeError, true);
    assertEq(Atomics.isLockFree(true), true);
    assertEq(Atomics.isLockFree(false), false);
    assertEq(Atomics.isLockFree(undefined), false);
    assertEq(Atomics.isLockFree(null), false);
    assertEq(Atomics.isLockFree({toString: () => '4'}), true);
    assertEq(Atomics.isLockFree({valueOf: () => 4}), true);
    assertEq(Atomics.isLockFree({valueOf: () => 5}), false);
    assertEq(Atomics.isLockFree({password: "qumquat"}), false);
}

function testUint8Clamped(sab) {
    var ta = new Uint8ClampedArray(sab);
    var thrown = false;
    try {
	CLONE(testMethod)(ta, 0);
    }
    catch (e) {
	thrown = true;
	assertEq(e instanceof TypeError, true);
    }
    assertEq(thrown, true);
}

function testWeirdIndices() {
    var a = new Int8Array(new SharedArrayBuffer(16));
    a[3] = 10;
    assertEq(Atomics.load(a, "0x03"), 10);
    assertEq(Atomics.load(a, {valueOf: () => 3}), 10);
}

function isLittleEndian() {
    var xxx = new ArrayBuffer(2);
    var xxa = new Int16Array(xxx);
    var xxb = new Int8Array(xxx);
    xxa[0] = 37;
    var is_little = xxb[0] == 37;
    return is_little;
}

function runTests() {
    var is_little = isLittleEndian();

    // Currently the SharedArrayBuffer needs to be a multiple of 4K bytes in size.
    var sab = new SharedArrayBuffer(4096);

    // Test that two arrays created on the same storage alias
    var t1 = new Int8Array(sab);
    var t2 = new Uint16Array(sab);

    assertEq(t1[0], 0);
    assertEq(t2[0], 0);
    t1[0] = 37;
    if (is_little)
	assertEq(t2[0], 37);
    else
	assertEq(t2[0], 37 << 8);
    t1[0] = 0;

    // Test that invoking as Atomics.whatever() works, on correct arguments.
    CLONE(testMethod)(new Int8Array(sab), 0, 42, 4095);
    CLONE(testMethod)(new Uint8Array(sab), 0, 42, 4095);
    CLONE(testMethod)(new Int16Array(sab), 0, 42, 2047);
    CLONE(testMethod)(new Uint16Array(sab), 0, 42, 2047);
    CLONE(testMethod)(new Int32Array(sab), 0, 42, 1023);
    CLONE(testMethod)(new Uint32Array(sab), 0, 42, 1023);

    // Test that invoking as v = Atomics.whatever; v() works, on correct arguments.
    gAtomics_compareExchange = Atomics.compareExchange;
    gAtomics_exchange = Atomics.exchange;
    gAtomics_load = Atomics.load;
    gAtomics_store = Atomics.store;
    gAtomics_add = Atomics.add;
    gAtomics_sub = Atomics.sub;
    gAtomics_and = Atomics.and;
    gAtomics_or = Atomics.or;
    gAtomics_xor = Atomics.xor;

    CLONE(testFunction)(new Int8Array(sab), 0, 42, 4095);
    CLONE(testFunction)(new Uint8Array(sab), 0, 42, 4095);
    CLONE(testFunction)(new Int16Array(sab), 0, 42, 2047);
    CLONE(testFunction)(new Uint16Array(sab), 0, 42, 2047);
    CLONE(testFunction)(new Int32Array(sab), 0, 42, 1023);
    CLONE(testFunction)(new Uint32Array(sab), 0, 42, 1023);

    // Test various range and type conditions
    var v8 = new Int8Array(sab);
    var v32 = new Int32Array(sab);

    CLONE(testTypeCAS)(v8);
    CLONE(testTypeCAS)(v32);

    CLONE(testTypeBinop)(v8, Atomics.add);
    CLONE(testTypeBinop)(v8, Atomics.sub);
    CLONE(testTypeBinop)(v8, Atomics.and);
    CLONE(testTypeBinop)(v8, Atomics.or);
    CLONE(testTypeBinop)(v8, Atomics.xor);

    CLONE(testTypeBinop)(v32, Atomics.add);
    CLONE(testTypeBinop)(v32, Atomics.sub);
    CLONE(testTypeBinop)(v32, Atomics.and);
    CLONE(testTypeBinop)(v32, Atomics.or);
    CLONE(testTypeBinop)(v32, Atomics.xor);

    // Test out-of-range references
    globlength = v8.length + 5;
    CLONE(testRangeCAS)(v8);
    globlength = v32.length + 5;
    CLONE(testRangeCAS)(v32);

    // Test extreme values
    testInt8Extremes(new Int8Array(sab));
    testUint8Extremes(new Uint8Array(sab));
    testInt16Extremes(new Int16Array(sab));
    testUint32(new Uint32Array(sab));

    // Test that Uint8ClampedArray is not accepted.
    testUint8Clamped(sab);

    // Misc ad-hoc tests
    adHocExchange();

    // Misc
    testIsLockFree();
    testIsLockFree2();
    testWeirdIndices();

    assertEq(Atomics[Symbol.toStringTag], "Atomics");
}

runTests();

vs

load(libdir + "asserts.js");

var DEBUG = false;

function dprint(xs) {
    if (!DEBUG) return;

    var s = "";
    for (x in xs) s += String(xs[x]);
    print(s);
}

function CLONE(f) {
    return this.eval("(" + f.toSource() + ")");
}

function testMethod(a, indices) {
    dprint("Method: " + a.constructor.name);
    var poison;
    switch (a.BYTES_PER_ELEMENT) {
        case 1:
            poison = 0x5A;

        break;

        case 2:
            poison = 0x5A5A;

        break;

        case 4:
            poison = 0x5A5A5A5A;

        break;

    }
    for (let i = 0;i < indices.length;i++) {
        var x = indices[i];

        if (x > 0) a[x - 1] = poison;


        if (x < a.length - 1) a[x + 1] = poison;


        assertEq(Atomics.compareExchange(a, x, 0, 37), 0);

        assertEq(Atomics.compareExchange(a, x, 37, 5), 37);

        assertEq(Atomics.compareExchange(a, x, 7, 8), 5);

        assertEq(Atomics.compareExchange(a, x, 5, 9), 5);

        assertEq(Atomics.compareExchange(a, x, 5, 0), 9);

        assertEq(Atomics.exchange(a, x, 4), 9);

        assertEq(Atomics.exchange(a, x, 9), 4);

        assertEq(Atomics.load(a, x), 9);

        assertEq(Atomics.store(a, x, 14), 14);

        assertEq(Atomics.load(a, x), 14);

        Atomics.store(a, x, 0);

        assertEq(Atomics.add(a, x, 3), 0);

        assertEq(Atomics.sub(a, x, 2), 3);

        assertEq(Atomics.or(a, x, 6), 1);

        assertEq(Atomics.and(a, x, 14), 7);

        assertEq(Atomics.xor(a, x, 5), 6);

        assertEq(Atomics.load(a, x), 3);

        Atomics.store(a, x, 0);

        if (x > 0) {
            assertEq(a[x - 1], poison);

            a[x - 1] = 0;
        }

        if (x < a.length - 1) {
            assertEq(a[x + 1], poison);

            a[x + 1] = 0;
        }
    }
}

function testFunction(a, indices) {
    dprint("Function: " + a.constructor.name);
    var poison;
    switch (a.BYTES_PER_ELEMENT) {
        case 1:
            poison = 0x5A;

        break;

        case 2:
            poison = 0x5A5A;

        break;

        case 4:
            poison = 0x5A5A5A5A;

        break;

    }
    for (let i = 0;i < indices.length;i++) {
        var x = indices[i];

        if (x > 0) a[x - 1] = poison;


        if (x < a.length - 1) a[x + 1] = poison;


        assertEq(gAtomics_compareExchange(a, x, 0, 37), 0);

        assertEq(gAtomics_compareExchange(a, x, 37, 5), 37);

        assertEq(gAtomics_compareExchange(a, x, 7, 8), 5);

        assertEq(gAtomics_compareExchange(a, x, 5, 9), 5);

        assertEq(gAtomics_compareExchange(a, x, 5, 0), 9);

        assertEq(gAtomics_exchange(a, x, 4), 9);

        assertEq(gAtomics_exchange(a, x, 9), 4);

        assertEq(gAtomics_load(a, x), 9);

        assertEq(gAtomics_store(a, x, 14), 14);

        assertEq(gAtomics_load(a, x), 14);

        gAtomics_store(a, x, 0);

        assertEq(gAtomics_add(a, x, 3), 0);

        assertEq(gAtomics_sub(a, x, 2), 3);

        assertEq(gAtomics_or(a, x, 6), 1);

        assertEq(gAtomics_and(a, x, 14), 7);

        assertEq(gAtomics_xor(a, x, 5), 6);

        assertEq(gAtomics_load(a, x), 3);

        gAtomics_store(a, x, 0);

        if (x > 0) {
            assertEq(a[x - 1], poison);

            a[x - 1] = 0;
        }

        if (x < a.length - 1) {
            assertEq(a[x + 1], poison);

            a[x + 1] = 0;
        }
    }
}

function testTypeCAS(a) {
    dprint("Type: " + a.constructor.name);
    var thrown = false;
    try {
        Atomics.compareExchange([0,], 0, 0, 1);
    } catch (e) {
        thrown = true;

        assertEq(e instanceof TypeError, true);
    }
    assertEq(thrown, true);
    Atomics.compareExchange(a, 0, 0.7, 1.8);
    Atomics.compareExchange(a, 0, "0", 1);
    Atomics.compareExchange(a, 0, 0, "1");
    Atomics.compareExchange(a, 0, 0);
}

function testTypeBinop(a, op) {
    dprint("Type: " + a.constructor.name);
    var thrown = false;
    try {
        op([0,], 0, 1);
    } catch (e) {
        thrown = true;

        assertEq(e instanceof TypeError, true);
    }
    assertEq(thrown, true);
    op(a, 0, 0.7);
    op(a, 0, "0");
    op(a, 0);
}

var globlength = 0;

function testRangeCAS(a) {
    dprint("Range: " + a.constructor.name);
    var msg = /out-of-range index/;
    assertErrorMessage(()  => Atomics.compareExchange(a, -1, 0, 1), RangeError, msg);
    assertEq(a[0], 0);
    assertEq(Atomics.compareExchange(a, "hi", 0, 33), 0);
    assertEq(a[0], 33);
    a[0] = 0;
    assertErrorMessage(()  => Atomics.compareExchange(a, a.length + 5, 0, 1), RangeError, msg);
    assertEq(a[0], 0);
    assertErrorMessage(()  => Atomics.compareExchange(a, globlength, 0, 1), RangeError, msg);
    assertEq(a[0], 0);
}

function testInt8Extremes(a) {
    dprint("Int8 extremes");
    a[10] = 0;
    a[11] = 0;
    Atomics.store(a, 10, 255);
    assertEq(a[10], -1);
    assertEq(Atomics.load(a, 10), -1);
    Atomics.add(a, 10, 255);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.add(a, 10, -1);
    assertEq(a[10], -3);
    assertEq(Atomics.load(a, 10), -3);
    Atomics.sub(a, 10, 255);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.sub(a, 10, 256);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.and(a, 10, -1);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.and(a, 10, 256);
    assertEq(a[10], 0);
    assertEq(Atomics.load(a, 10), 0);
    Atomics.store(a, 10, 255);
    assertEq(Atomics.exchange(a, 10, 0), -1);
    assertEq(a[11], 0);
}

function testUint8Extremes(a) {
    dprint("Uint8 extremes");
    a[10] = 0;
    a[11] = 0;
    Atomics.store(a, 10, 255);
    assertEq(a[10], 255);
    assertEq(Atomics.load(a, 10), 255);
    Atomics.add(a, 10, 255);
    assertEq(a[10], 254);
    assertEq(Atomics.load(a, 10), 254);
    Atomics.add(a, 10, -1);
    assertEq(a[10], 253);
    assertEq(Atomics.load(a, 10), 253);
    Atomics.sub(a, 10, 255);
    assertEq(a[10], 254);
    assertEq(Atomics.load(a, 10), 254);
    Atomics.and(a, 10, -1);
    assertEq(a[10], 254);
    assertEq(Atomics.load(a, 10), 254);
    Atomics.and(a, 10, 256);
    assertEq(a[10], 0);
    assertEq(Atomics.load(a, 10), 0);
    Atomics.store(a, 10, 255);
    assertEq(Atomics.exchange(a, 10, 0), 255);
    assertEq(a[11], 0);
}

function testInt16Extremes(a) {
    dprint("Int16 extremes");
    a[10] = 0;
    a[11] = 0;
    Atomics.store(a, 10, 65535);
    assertEq(a[10], -1);
    assertEq(Atomics.load(a, 10), -1);
    Atomics.add(a, 10, 65535);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.add(a, 10, -1);
    assertEq(a[10], -3);
    assertEq(Atomics.load(a, 10), -3);
    Atomics.sub(a, 10, 65535);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.sub(a, 10, 65536);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.and(a, 10, -1);
    assertEq(a[10], -2);
    assertEq(Atomics.load(a, 10), -2);
    Atomics.and(a, 10, 65536);
    assertEq(a[10], 0);
    assertEq(Atomics.load(a, 10), 0);
    assertEq(a[11], 0);
}

function testUint32(a) {
    var k = 0;
    for (let i = 0;i < 20;i++) {
        a[i] = i + 5;

        k += a[i];
    }
    var sum = 0;
    for (let i = 0;i < 20;i++) sum += Atomics.add(a, i, 1);
    assertEq(sum, k);
}

function exchangeLoop(ta) {
    var sum = 0;
    for (let i = 0;i < 100000;i++) sum += Atomics.exchange(ta, i & 15, 255);
    return sum;
}

function adHocExchange() {
    var a = new Int8Array(new SharedArrayBuffer(16));
    for (let i = 0;i < a.length;i++) a[i] = 255;
    assertEq(exchangeLoop(a), -100000);
}

var sizes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,];

var answers = [true, true, false, true, false, false, false, false, false, false, false, false,];

function testIsLockFree() {
    for (let i = 0;i < sizes.length;i++) {
        var v = Atomics.isLockFree(sizes[i]);

        var a = answers[i];

        assertEq(typeof v, 'boolean');

        assertEq(v, a);
    }
    assertEq(Atomics.isLockFree(1), true);
    assertEq(Atomics.isLockFree(2), true);
    assertEq(Atomics.isLockFree(3), false);
    assertEq(Atomics.isLockFree(4), true);
    assertEq(Atomics.isLockFree(5), false);
    assertEq(Atomics.isLockFree(6), false);
    assertEq(Atomics.isLockFree(7), false);
    assertEq(Atomics.isLockFree(8), false);
    assertEq(Atomics.isLockFree(9), false);
    assertEq(Atomics.isLockFree(10), false);
    assertEq(Atomics.isLockFree(11), false);
    assertEq(Atomics.isLockFree(12), false);
}

function testIsLockFree2() {
    assertEq(Atomics.isLockFree(0), false);
    assertEq(Atomics.isLockFree(0 / -1), false);
    assertEq(Atomics.isLockFree(3.5), false);
    assertEq(Atomics.isLockFree(Number.NaN), false);
    assertEq(Atomics.isLockFree(Number.POSITIVE_INFINITY), false);
    assertEq(Atomics.isLockFree(Number.NEGATIVE_INFINITY), false);
    assertEq(Atomics.isLockFree(-4), false);
    assertEq(Atomics.isLockFree('4'), true);
    assertEq(Atomics.isLockFree('-4'), false);
    assertEq(Atomics.isLockFree('4.5'), true);
    assertEq(Atomics.isLockFree('5.5'), false);
    assertEq(Atomics.isLockFree(new Number(4)), true);
    assertEq(Atomics.isLockFree(new String('4')), true);
    assertEq(Atomics.isLockFree(new Boolean(true)), true);
    var thrown = false;
    try {
        Atomics.isLockFree(Symbol('1'));
    } catch (e) {
        thrown = e;
    }
    assertEq(thrown instanceof TypeError, true);
    assertEq(Atomics.isLockFree(true), true);
    assertEq(Atomics.isLockFree(false), false);
    assertEq(Atomics.isLockFree(undefined), false);
    assertEq(Atomics.isLockFree(null), false);
    assertEq(Atomics.isLockFree({
        toString: ()  => '4',
    }), true);
    assertEq(Atomics.isLockFree({
        valueOf: ()  => 4,
    }), true);
    assertEq(Atomics.isLockFree({
        valueOf: ()  => 5,
    }), false);
    assertEq(Atomics.isLockFree({
        password: "qumquat",
    }), false);
}

function testUint8Clamped(sab) {
    var ta = new Uint8ClampedArray(sab);
    var thrown = false;
    try {
        CLONE(testMethod)(ta, 0);
    } catch (e) {
        thrown = true;

        assertEq(e instanceof TypeError, true);
    }
    assertEq(thrown, true);
}

function testWeirdIndices() {
    var a = new Int8Array(new SharedArrayBuffer(16));
    a[3] = 10;
    assertEq(Atomics.load(a, "0x03"), 10);
    assertEq(Atomics.load(a, {
        valueOf: ()  => 3,
    }), 10);
}

function isLittleEndian() {
    var xxx = new ArrayBuffer(2);
    var xxa = new Int16Array(xxx);
    var xxb = new Int8Array(xxx);
    xxa[0] = 37;
    var is_little = xxb[0] == 37;
    return is_little;
}

function runTests() {
    var is_little = isLittleEndian();
    var sab = new SharedArrayBuffer(4096);
    var t1 = new Int8Array(sab);
    var t2 = new Uint16Array(sab);
    assertEq(t1[0], 0);
    assertEq(t2[0], 0);
    t1[0] = 37;
    if (is_little) assertEq(t2[0], 37);
 else assertEq(t2[0], 37 << 8);

    t1[0] = 0;
    CLONE(testMethod)(new Int8Array(sab), 0, 42, 4095);
    CLONE(testMethod)(new Uint8Array(sab), 0, 42, 4095);
    CLONE(testMethod)(new Int16Array(sab), 0, 42, 2047);
    CLONE(testMethod)(new Uint16Array(sab), 0, 42, 2047);
    CLONE(testMethod)(new Int32Array(sab), 0, 42, 1023);
    CLONE(testMethod)(new Uint32Array(sab), 0, 42, 1023);
    gAtomics_compareExchange = Atomics.compareExchange;
    gAtomics_exchange = Atomics.exchange;
    gAtomics_load = Atomics.load;
    gAtomics_store = Atomics.store;
    gAtomics_add = Atomics.add;
    gAtomics_sub = Atomics.sub;
    gAtomics_and = Atomics.and;
    gAtomics_or = Atomics.or;
    gAtomics_xor = Atomics.xor;
    CLONE(testFunction)(new Int8Array(sab), 0, 42, 4095);
    CLONE(testFunction)(new Uint8Array(sab), 0, 42, 4095);
    CLONE(testFunction)(new Int16Array(sab), 0, 42, 2047);
    CLONE(testFunction)(new Uint16Array(sab), 0, 42, 2047);
    CLONE(testFunction)(new Int32Array(sab), 0, 42, 1023);
    CLONE(testFunction)(new Uint32Array(sab), 0, 42, 1023);
    var v8 = new Int8Array(sab);
    var v32 = new Int32Array(sab);
    CLONE(testTypeCAS)(v8);
    CLONE(testTypeCAS)(v32);
    CLONE(testTypeBinop)(v8, Atomics.add);
    CLONE(testTypeBinop)(v8, Atomics.sub);
    CLONE(testTypeBinop)(v8, Atomics.and);
    CLONE(testTypeBinop)(v8, Atomics.or);
    CLONE(testTypeBinop)(v8, Atomics.xor);
    CLONE(testTypeBinop)(v32, Atomics.add);
    CLONE(testTypeBinop)(v32, Atomics.sub);
    CLONE(testTypeBinop)(v32, Atomics.and);
    CLONE(testTypeBinop)(v32, Atomics.or);
    CLONE(testTypeBinop)(v32, Atomics.xor);
    globlength = v8.length + 5;
    CLONE(testRangeCAS)(v8);
    globlength = v32.length + 5;
    CLONE(testRangeCAS)(v32);
    testInt8Extremes(new Int8Array(sab));
    testUint8Extremes(new Uint8Array(sab));
    testInt16Extremes(new Int16Array(sab));
    testUint32(new Uint32Array(sab));
    testUint8Clamped(sab);
    adHocExchange();
    testIsLockFree();
    testIsLockFree2();
    testWeirdIndices();
    assertEq(Atomics[Symbol.toStringTag], "Atomics");
}

runTests();
function test_syntax(postfixes, check_error, ignore_opts) {
  function test_reflect(code, module) {
    var options = undefined;
    if (module) {
      options = {target: "module"};
    }
    for (var postfix of postfixes) {
      var cur_code = code + postfix;

      var caught = false;
      try {
        Reflect.parse(cur_code, options);
      } catch (e) {
        caught = true;
        check_error(e, cur_code, "reflect");
      }
      assertEq(caught, true);
    }
  }

  function test_eval(code) {
    for (var postfix of postfixes) {
      var cur_code = code + postfix;

      var caught = false;
      try {
        eval(cur_code);
      } catch (e) {
        caught = true;
        check_error(e, cur_code, "eval");
      }
      assertEq(caught, true);
    }
  }

  function test(code, opts={}) {
    if (ignore_opts) {
      opts = {};
    }

    let no_strict = "no_strict" in opts && opts.no_strict;
    let no_fun = "no_fun" in opts && opts.no_fun;
    let no_eval = "no_eval" in opts && opts.no_eval;
    let module = "module" in opts && opts.module;

    test_reflect(code, module);
    if (!no_strict) {
      test_reflect("'use strict'; " + code, module);
    }
    if (!no_fun) {
      test_reflect("(function() { " + code, module);
      if (!no_strict) {
        test_reflect("(function() { 'use strict'; " + code, module);
      }
    }

    if (!no_eval) {
      test_eval(code);
      if (!no_strict) {
        test_eval("'use strict'; " + code);
      }
      if (!no_fun) {
        test_eval("(function() { " + code);
        if (!no_strict) {
          test_eval("(function() { 'use strict'; " + code);
        }
      }
    }
  }

  function test_fun_arg(arg) {
    for (var postfix of postfixes) {
      var cur_arg = arg + postfix;

      var caught = false;
      try {
        new Function(cur_arg, "");
      } catch (e) {
        caught = true;
        check_error(e, cur_arg, "fun_arg");
      }
      assertEq(caught, true);
    }
  }

  // ==== Statements and declarations ====

  // ---- Control flow ----

  // Block

  test("{ ");
  test("{ } ");

  test("{ 1 ");
  test("{ 1; ");
  test("{ 1; } ");

  // break

  test("a: for (;;) { break ");
  test("a: for (;;) { break; ");
  test("a: for (;;) { break a ");
  test("a: for (;;) { break a; ");

  test("a: for (;;) { break\n");

  // continue

  test("a: for (;;) { continue ");
  test("a: for (;;) { continue; ");
  test("a: for (;;) { continue a ");
  test("a: for (;;) { continue a; ");

  test("a: for (;;) { continue\n");

  // Empty

  test("");
  test("; ");

  // if...else

  test("if ");
  test("if (");
  test("if (x ");
  test("if (x) ");
  test("if (x) { ");
  test("if (x) {} ");
  test("if (x) {} else ");
  test("if (x) {} else { ");
  test("if (x) {} else {} ");
  test("if (x) x ");
  test("if (x) x; ");
  test("if (x) x; else ");
  test("if (x) x; else y ");
  test("if (x) x; else y; ");

  // switch

  test("switch ");
  test("switch (");
  test("switch (x ");
  test("switch (x) ");
  test("switch (x) { ");
  test("switch (x) { case ");
  test("switch (x) { case 1 ");
  test("switch (x) { case 1: ");
  test("switch (x) { case 1: case ");
  test("switch (x) { case 1: case 2 ");
  test("switch (x) { case 1: case 2: ");
  test("switch (x) { case 1: case 2: x ");
  test("switch (x) { case 1: case 2: x; ");
  test("switch (x) { case 1: case 2: x; break ");
  test("switch (x) { case 1: case 2: x; break; ");
  test("switch (x) { case 1: case 2: x; break; case ");
  test("switch (x) { case 1: case 2: x; break; case 3 ");
  test("switch (x) { case 1: case 2: x; break; case 3: y ");
  test("switch (x) { case 1: case 2: x; break; case 3: y; ");
  test("switch (x) { case 1: case 2: x; break; case 3: y; default ");
  test("switch (x) { case 1: case 2: x; break; case 3: y; default: ");
  test("switch (x) { case 1: case 2: x; break; case 3: y; default: z ");
  test("switch (x) { case 1: case 2: x; break; case 3: y; default: z; ");
  test("switch (x) { case 1: case 2: x; break; case 3: y; default: z; } ");

  // throw

  test("throw ");
  test("throw x ");
  test("throw x; ");

  // try...catch

  test("try ");
  test("try { ");
  test("try {} ");
  test("try {} catch ");
  test("try {} catch ( ");
  test("try {} catch (e ");
  test("try {} catch (e) ");
  test("try {} catch (e) { ");
  test("try {} catch (e) {} ");
  test("try {} catch (e) {} finally ");
  test("try {} catch (e) {} finally { ");
  test("try {} catch (e) {} finally {} ");

  // ---- Declarations ----

  // var

  test("var ");
  test("var x ");
  test("var x = ");
  test("var x = 1 ");
  test("var x = 1 + ");
  test("var x = 1 + 2 ");
  test("var x = 1 + 2, ");
  test("var x = 1 + 2, y ");
  test("var x = 1 + 2, y, ");
  test("var x = 1 + 2, y, z ");
  test("var x = 1 + 2, y, z; ");

  test("var [ ");
  test("var [ x ");
  test("var [ x, ");
  test("var [ x, ... ");
  test("var { ");
  test("var { x ");
  test("var { x: ");
  test("var { x: y ");
  test("var { x: y, ");
  test("var { x: y } ");
  test("var { x: y } = ");

  // let

  test("let ");
  test("let x ");
  test("let x = ");
  test("let x = 1 ");
  test("let x = 1 + ");
  test("let x = 1 + 2 ");
  test("let x = 1 + 2, ");
  test("let x = 1 + 2, y ");
  test("let x = 1 + 2, y, ");
  test("let x = 1 + 2, y, z ");
  test("let x = 1 + 2, y, z; ");

  test("let [ ");
  test("let [ x ");
  test("let [ x, ");
  test("let [ x, ... ");
  test("let { ");
  test("let { x ");
  test("let { x: ");
  test("let { x: y ");
  test("let { x: y, ");
  test("let { x: y } ");
  test("let { x: y } = ");

  // const

  test("const ");
  test("const x ");
  test("const x = ");
  test("const x = 1 ");
  test("const x = 1 + ");
  test("const x = 1 + 2 ");
  test("const x = 1 + 2, ");
  test("const x = 1 + 2, y = 0");
  test("const x = 1 + 2, y = 0, ");
  test("const x = 1 + 2, y = 0, z = 0 ");
  test("const x = 1 + 2, y = 0, z = 0; ");

  test("const [ ");
  test("const [ x ");
  test("const [ x, ");
  test("const [ x, ... ");
  test("const { ");
  test("const { x ");
  test("const { x: ");
  test("const { x: y ");
  test("const { x: y, ");
  test("const { x: y } ");
  test("const { x: y } = ");

  // ---- Functions ----

  // function

  test("function ");
  test("function f ");
  test("function f( ");
  test("function f(x ");
  test("function f(x, ");
  test("function f(x, [ ");
  test("function f(x, [y ");
  test("function f(x, [y, ");
  test("function f(x, [y, { ");
  test("function f(x, [y, {z ");
  test("function f(x, [y, {z: ");
  test("function f(x, [y, {z: zz ");
  test("function f(x, [y, {z: zz,  ");
  test("function f(x, [y, {z: zz, w ");
  test("function f(x, [y, {z: zz, w} ");
  test("function f(x, [y, {z: zz, w}] ");
  test("function f(x, [y, {z: zz, w}], ");
  test("function f(x, [y, {z: zz, w}], v ");
  test("function f(x, [y, {z: zz, w}], v= ");
  test("function f(x, [y, {z: zz, w}], v=1 ");
  test("function f(x, [y, {z: zz, w}], v=1, ");
  test("function f(x, [y, {z: zz, w}], v=1, ... ");
  test("function f(x, [y, {z: zz, w}], v=1, ...t ");
  test("function f(x, [y, {z: zz, w}], v=1, ...t) ");
  test("function f(x, [y, {z: zz, w}], v=1, ...t) {");
  test("function f(x, [y, {z: zz, w}], v=1, ...t) { x ");
  test("function f(x, [y, {z: zz, w}], v=1, ...t) { x; ");
  test("function f(x, [y, {z: zz, w}], v=1, ...t) { x; } ");

  // star function

  test("function* ");
  test("function* f ");
  test("function* f( ");
  test("function* f(x ");
  test("function* f(x, ");
  test("function* f(x, ... ");
  test("function* f(x, ...t ");
  test("function* f(x, ...t) ");
  test("function* f(x, ...t) {");
  test("function* f(x, ...t) { x ");
  test("function* f(x, ...t) { x; ");
  test("function* f(x, ...t) { x; } ");

  // return

  test("function f() { return ");
  test("function f() { return 1 ");
  test("function f() { return 1; ");
  test("function f() { return 1; } ");
  test("function f() { return; ");
  test("function f() { return\n");

  // yield

  test("function* f() { yield ");
  test("function* f() { yield 1 ");
  test("function* f() { yield* ");
  test("function* f() { yield* 1 ");

  test("function* f() { yield\n");
  test("function* f() { yield*\n");

  // ---- Iterations ----

  // do...while

  test("do ");
  test("do {");
  test("do {} ");
  test("do {} while ");
  test("do {} while ( ");
  test("do {} while (x ");
  test("do {} while (x) ");
  test("do {} while (x); ");

  test("do x ");
  test("do x; ");
  test("do x; while ");

  // for

  test("for ");
  test("for (");
  test("for (x ");
  test("for (x; ");
  test("for (x; y ");
  test("for (x; y; ");
  test("for (x; y; z ");
  test("for (x; y; z) ");
  test("for (x; y; z) { ");
  test("for (x; y; z) {} ");

  test("for (x; y; z) x ");
  test("for (x; y; z) x; ");

  test("for (var ");
  test("for (var x ");
  test("for (var x = ");
  test("for (var x = y ");
  test("for (var x = y; ");

  test("for (let ");
  test("for (let x ");
  test("for (let x = ");
  test("for (let x = y ");
  test("for (let x = y; ");

  // for...in

  test("for (x in ");
  test("for (x in y ");
  test("for (x in y) ");

  test("for (var x in ");
  test("for (var x in y ");
  test("for (var x in y) ");

  test("for (let x in ");
  test("for (let x in y ");
  test("for (let x in y) ");

  // for...of

  test("for (x of ");
  test("for (x of y ");
  test("for (x of y) ");

  test("for (var x of ");
  test("for (var x of y ");
  test("for (var x of y) ");

  test("for (let x of ");
  test("for (let x of y ");
  test("for (let x of y) ");

  // while

  test("while ");
  test("while (");
  test("while (x ");
  test("while (x) ");
  test("while (x) { ");
  test("while (x) {} ");

  test("while (x) x ");
  test("while (x) x; ");

  // ---- Others ----

  // debugger

  test("debugger ");
  test("debugger; ");

  // export

  var opts = { no_fun: true, no_eval: true, module: true };
  test("export ", opts);
  test("export { ", opts);
  test("export { x ", opts);
  test("export { x, ", opts);
  test("export { x, y ", opts);
  test("export { x, y as ", opts);
  test("export { x, y as z ", opts);
  test("export { x, y as z } ", opts);
  test("export { x, y as z } from ", opts);
  test("export { x, y as z } from 'a' ", opts);
  test("export { x, y as z } from 'a'; ", opts);

  test("export * ", opts);
  test("export * from ", opts);
  test("export * from 'a' ", opts);
  test("export * from 'a'; ", opts);

  test("export function ", opts);
  test("export function f ", opts);
  test("export function f( ", opts);
  test("export function f() ", opts);
  test("export function f() { ", opts);
  test("export function f() {} ", opts);
  test("export function f() {}; ", opts);

  test("export var ", opts);
  test("export var a ", opts);
  test("export var a = ", opts);
  test("export var a = 1 ", opts);
  test("export var a = 1, ", opts);
  test("export var a = 1, b ", opts);
  test("export var a = 1, b = ", opts);
  test("export var a = 1, b = 2 ", opts);
  test("export var a = 1, b = 2; ", opts);

  test("export let ", opts);
  test("export let a ", opts);
  test("export let a = ", opts);
  test("export let a = 1 ", opts);
  test("export let a = 1, ", opts);
  test("export let a = 1, b ", opts);
  test("export let a = 1, b = ", opts);
  test("export let a = 1, b = 2 ", opts);
  test("export let a = 1, b = 2; ", opts);

  test("export const ", opts);
  test("export const a ", opts);
  test("export const a = ", opts);
  test("export const a = 1 ", opts);
  test("export const a = 1, ", opts);
  test("export const a = 1, b ", opts);
  test("export const a = 1, b = ", opts);
  test("export const a = 1, b = 2 ", opts);
  test("export const a = 1, b = 2; ", opts);

  test("export class ", opts);
  test("export class Foo ", opts);
  test("export class Foo {  ", opts);
  test("export class Foo { constructor ", opts);
  test("export class Foo { constructor( ", opts);
  test("export class Foo { constructor() ", opts);
  test("export class Foo { constructor() { ", opts);
  test("export class Foo { constructor() {} ", opts);
  test("export class Foo { constructor() {} } ", opts);
  test("export class Foo { constructor() {} }; ", opts);

  test("export default ", opts);
  test("export default 1 ", opts);
  test("export default 1; ", opts);

  test("export default function ", opts);
  test("export default function() ", opts);
  test("export default function() { ", opts);
  test("export default function() {} ", opts);
  test("export default function() {}; ", opts);

  test("export default function foo ", opts);
  test("export default function foo( ", opts);
  test("export default function foo() ", opts);
  test("export default function foo() { ", opts);
  test("export default function foo() {} ", opts);
  test("export default function foo() {}; ", opts);

  test("export default class ", opts);
  test("export default class { ", opts);
  test("export default class { constructor ", opts);
  test("export default class { constructor( ", opts);
  test("export default class { constructor() ", opts);
  test("export default class { constructor() { ", opts);
  test("export default class { constructor() {} ", opts);
  test("export default class { constructor() {} } ", opts);
  test("export default class { constructor() {} }; ", opts);

  test("export default class Foo ", opts);
  test("export default class Foo { ", opts);
  test("export default class Foo { constructor ", opts);
  test("export default class Foo { constructor( ", opts);
  test("export default class Foo { constructor() ", opts);
  test("export default class Foo { constructor() { ", opts);
  test("export default class Foo { constructor() {} ", opts);
  test("export default class Foo { constructor() {} } ", opts);
  test("export default class Foo { constructor() {} }; ", opts);

  // import

  test("import ", opts);
  test("import x ", opts);
  test("import x from ", opts);
  test("import x from 'a' ", opts);
  test("import x from 'a'; ", opts);

  test("import { ", opts);
  test("import { x ", opts);
  test("import { x, ", opts);
  test("import { x, y ", opts);
  test("import { x, y } ", opts);
  test("import { x, y } from ", opts);
  test("import { x, y } from 'a' ", opts);
  test("import { x, y } from 'a'; ", opts);

  test("import { x as ", opts);
  test("import { x as y ", opts);
  test("import { x as y } ", opts);
  test("import { x as y } from ", opts);
  test("import { x as y } from 'a' ", opts);
  test("import { x as y } from 'a'; ", opts);

  test("import 'a' ", opts);
  test("import 'a'; ", opts);

  test("import * ", opts);
  test("import * as ", opts);
  test("import * as a ", opts);
  test("import * as a from ", opts);
  test("import * as a from 'a' ", opts);
  test("import * as a from 'a'; ", opts);

  test("import a ", opts);
  test("import a, ", opts);
  test("import a, * ", opts);
  test("import a, * as ", opts);
  test("import a, * as b ", opts);
  test("import a, * as b from ", opts);
  test("import a, * as b from 'c' ", opts);
  test("import a, * as b from 'c'; ", opts);

  test("import a, { ", opts);
  test("import a, { b ", opts);
  test("import a, { b } ", opts);
  test("import a, { b } from ", opts);
  test("import a, { b } from 'c' ", opts);
  test("import a, { b } from 'c'; ", opts);

  // label

  test("a ");
  test("a: ");

  // with

  opts = { no_strict: true };
  test("with ", opts);
  test("with (", opts);
  test("with (x ", opts);
  test("with (x) ", opts);
  test("with (x) { ", opts);
  test("with (x) {} ", opts);

  test("with (x) x ", opts);
  test("with (x) x; ", opts);

  // ==== Expressions and operators ====

  // ---- Primary expressions ----

  // this

  test("this ");

  // function

  test("(function ");
  test("(function ( ");
  test("(function (x ");
  test("(function (x, ");
  test("(function (x, ... ");
  test("(function (x, ...t ");
  test("(function (x, ...t) ");
  test("(function (x, ...t) {");
  test("(function (x, ...t) { x ");
  test("(function (x, ...t) { x; ");
  test("(function (x, ...t) { x; } ");
  test("(function (x, ...t) { x; }) ");

  // star function

  test("(function* ");
  test("(function* ( ");
  test("(function* (x ");
  test("(function* (x, ");
  test("(function* (x, ... ");
  test("(function* (x, ...t ");
  test("(function* (x, ...t) ");
  test("(function* (x, ...t) {");
  test("(function* (x, ...t) { x ");
  test("(function* (x, ...t) { x; ");
  test("(function* (x, ...t) { x; } ");
  test("(function* (x, ...t) { x; }) ");

  // Array literal

  test("[ ");
  test("[] ");
  test("[1 ");
  test("[1, ");
  test("[1, ... ");
  test("[1, ...x ");
  test("[1, ...x] ");

  // object

  test("({ ");
  test("({ x ");
  test("({ x: ");
  test("({ x: 1 ");
  test("({ x: 1, ");
  test("({ x: 1, y ");
  test("({ x: 1, y: ");
  test("({ x: 1, y: 2 ");
  test("({ x: 1, y: 2, ");
  test("({ x: 1, y: 2, z ");
  test("({ x: 1, y: 2, z, ");
  test("({ x: 1, y: 2, z, w ");
  test("({ x: 1, y: 2, z, w } ");
  test("({ x: 1, y: 2, z, w }) ");

  // object: computed property

  test("({ [");
  test("({ [k ");
  test("({ [k] ");
  test("({ [k]: ");
  test("({ [k]: 1 ");
  test("({ [k]: 1, ");

  // object: getter

  test("({ get ");
  test("({ get p ");
  test("({ get p( ");
  test("({ get p() ");
  test("({ get p() { ");
  test("({ get p() {} ");
  test("({ get p() {}, ");
  test("({ get p() {}, } ");

  test("({ get [ ");
  test("({ get [p ");
  test("({ get [p] ");
  test("({ get [p]( ");
  test("({ get [p]() ");

  // object: setter

  test("({ set ");
  test("({ set p ");
  test("({ set p( ");
  test("({ set p(v ");
  test("({ set p(v) ");
  test("({ set p(v) { ");
  test("({ set p(v) {} ");

  test("({ set [ ");
  test("({ set [p ");
  test("({ set [p] ");
  test("({ set [p]( ");
  test("({ set [p](v ");
  test("({ set [p](v) ");

  // object: method

  test("({ m ");
  test("({ m( ");
  test("({ m() ");
  test("({ m() { ");
  test("({ m() {} ");
  test("({ m() {}, ");

  test("({ [ ");
  test("({ [m ");
  test("({ [m] ");
  test("({ [m]( ");
  test("({ [m]() ");
  test("({ [m]() { ");
  test("({ [m]() {} ");
  test("({ [m]() {}, ");

  test("({ * ");
  test("({ *m ");
  test("({ *m( ");
  test("({ *m() ");
  test("({ *m() { ");
  test("({ *m() {} ");
  test("({ *m() {}, ");

  test("({ *[ ");
  test("({ *[m ");
  test("({ *[m] ");
  test("({ *[m]( ");
  test("({ *[m]() ");
  test("({ *[m]() { ");
  test("({ *[m]() {} ");
  test("({ *[m]() {}, ");

  test("({ * get ");
  test("({ * get ( ");
  test("({ * get () ");
  test("({ * get () { ");
  test("({ * get () {} ");
  test("({ * get () {}, ");

  test("({ * set ");
  test("({ * set ( ");
  test("({ * set () ");
  test("({ * set () { ");
  test("({ * set () {} ");
  test("({ * set () {}, ");

  // Regular expression literal

  test("/a/ ");
  test("/a/g ");

  // ---- Left-hand-side expressions ----

  // property access

  test("a[ ");
  test("a[1 ");
  test("a[1] ");

  test("a. ");
  test("a.b ");
  test("a.b; ");

  // new

  test("new ");
  test("new f ");
  test("new f( ");
  test("new f() ");
  test("new f(); ");

  // ---- Increment and decrement ----

  test("a ++ ");
  test("a ++; ");

  test("-- ");
  test("-- a ");
  test("-- a; ");

  // ---- Unary operators ----

  // delete

  test("delete ");
  test("delete a ");
  test("delete a[ ");
  test("delete a[b ");
  test("delete a[b] ");
  test("delete a[b]; ");

  test("delete ( ");
  test("delete (a ");
  test("delete (a[ ");
  test("delete (a[b ");
  test("delete (a[b] ");
  test("delete (a[b]) ");
  test("delete (a[b]); ");

  // void

  test("void ");
  test("void a ");
  test("void a; ");

  test("void (");
  test("void (a ");
  test("void (a) ");
  test("void (a); ");

  // typeof

  test("typeof ");
  test("typeof a ");
  test("typeof a; ");

  test("typeof (");
  test("typeof (a ");
  test("typeof (a) ");
  test("typeof (a); ");

  // -

  test("- ");
  test("- 1 ");
  test("- 1; ");

  // +

  test("+ ");
  test("+ 1 ");
  test("+ 1; ");

  // ---- Arithmetic operators ----

  // +

  test("1 + ");
  test("1 + 1 ");
  test("1 + 1; ");

  // ---- Relational operators ----

  // in

  test("a in ");
  test("a in b ");
  test("a in b; ");

  // instanceof

  test("a instanceof ");
  test("a instanceof b ");
  test("a instanceof b; ");

  // ---- Equality operators ----

  // ==

  test("1 == ");
  test("1 == 1 ");
  test("1 == 1; ");

  // ---- Bitwise shift operators ----

  // <<

  test("1 << ");
  test("1 << 1 ");
  test("1 << 1; ");

  // ---- Binary bitwise operators ----

  // &

  test("1 & ");
  test("1 & 1 ");
  test("1 & 1; ");

  // ---- Binary logical operators ----

  // ||

  test("1 || ");
  test("1 || 1 ");
  test("1 || 1; ");

  // ---- Conditional (ternary) operator ----

  test("1 ? ");
  test("1 ? 2 ");
  test("1 ? 2 : ");
  test("1 ? 2 : 3 ");
  test("1 ? 2 : 3; ");

  // ---- Assignment operators ----

  test("x = ");
  test("x = 1 ");
  test("x = 1 + ");
  test("x = 1 + 2 ");
  test("x = 1 + 2; ");

  // ---- Comma operator ----

  test("1, ");
  test("1, 2 ");
  test("1, 2; ");

  // ---- Functions ----

  // Arrow functions

  test("a => ");
  test("a => 1 ");
  test("a => 1; ");
  test("a => { ");
  test("a => {} ");
  test("a => {}; ");

  test("( ");
  test("() ");
  test("() => ");

  test("(...");
  test("(...a ");
  test("(...a) ");
  test("(...a) => ");

  test("([ ");
  test("([a ");
  test("([a] ");
  test("([a]) ");
  test("([a]) => ");

  test("({ ");
  test("({a ");
  test("({a} ");
  test("({a}) ");
  test("({a}) => ");
  test("({a: ");
  test("({a: b ");
  test("({a: b, ");
  test("({a: b} ");
  test("({a: b}) ");
  test("({a: b}) => ");

  // ---- Class declaration ----

  test("class ");
  test("class a ");
  test("class a { ");
  test("class a { constructor ");
  test("class a { constructor( ");
  test("class a { constructor() ");
  test("class a { constructor() { ");
  test("class a { constructor() { } ");
  test("class a { constructor() { } } ");

  test("class a { constructor() { } static ");
  test("class a { constructor() { } static m ");
  test("class a { constructor() { } static m( ");
  test("class a { constructor() { } static m() ");
  test("class a { constructor() { } static m() { ");
  test("class a { constructor() { } static m() {} ");
  test("class a { constructor() { } static m() {} } ");

  test("class a { constructor() { } static ( ");
  test("class a { constructor() { } static () ");
  test("class a { constructor() { } static () { ");
  test("class a { constructor() { } static () {} ");
  test("class a { constructor() { } static () {} } ");

  test("class a { constructor() { } static get ");
  test("class a { constructor() { } static get p ");
  test("class a { constructor() { } static get p( ");
  test("class a { constructor() { } static get p() ");
  test("class a { constructor() { } static get p() { ");
  test("class a { constructor() { } static get p() {} ");
  test("class a { constructor() { } static get p() {} } ");

  test("class a { constructor() { } static set ");
  test("class a { constructor() { } static set p ");
  test("class a { constructor() { } static set p( ");
  test("class a { constructor() { } static set p(v ");
  test("class a { constructor() { } static set p(v) ");
  test("class a { constructor() { } static set p(v) { ");
  test("class a { constructor() { } static set p(v) {} ");
  test("class a { constructor() { } static set p(v) {} } ");

  test("class a { constructor() { } * ");
  test("class a { constructor() { } *m ");
  test("class a { constructor() { } *m( ");
  test("class a { constructor() { } *m() ");
  test("class a { constructor() { } *m() { ");
  test("class a { constructor() { } *m() {} ");
  test("class a { constructor() { } *m() {} } ");

  test("class a { constructor() { } static * ");
  test("class a { constructor() { } static *m ");
  test("class a { constructor() { } static *m( ");
  test("class a { constructor() { } static *m() ");
  test("class a { constructor() { } static *m() { ");
  test("class a { constructor() { } static *m() {} ");
  test("class a { constructor() { } static *m() {} } ");

  test("class a extends ");
  test("class a extends b ");
  test("class a extends b { ");

  test("class a extends ( ");
  test("class a extends ( b ");
  test("class a extends ( b ) ");
  test("class a extends ( b ) { ");

  // ---- Class expression ----

  test("( class ");
  test("( class a ");
  test("( class a { ");
  test("( class a { constructor ");
  test("( class a { constructor( ");
  test("( class a { constructor() ");
  test("( class a { constructor() { ");
  test("( class a { constructor() { } ");
  test("( class a { constructor() { } } ");
  test("( class a { constructor() { } } ) ");

  test("(class a extends ");
  test("(class a extends b ");
  test("(class a extends b { ");

  test("(class a extends ( ");
  test("(class a extends ( b ");
  test("(class a extends ( b ) ");
  test("(class a extends ( b ) { ");

  test("( class { ");
  test("( class { constructor ");
  test("( class { constructor( ");
  test("( class { constructor() ");
  test("( class { constructor() { ");
  test("( class { constructor() { } ");
  test("( class { constructor() { } } ");
  test("( class { constructor() { } } ) ");

  test("(class extends ");
  test("(class extends b ");
  test("(class extends b { ");

  test("(class extends ( ");
  test("(class extends ( b ");
  test("(class extends ( b ) ");
  test("(class extends ( b ) { ");

  // ---- Other ----

  // Literals

  test("a ");
  test("1 ");
  test("1. ");
  test("1.2 ");
  test("true ");
  test("false ");
  test("\"a\" ");
  test("'a' ");
  test("null ");

  // Template strings

  test("`${ ");
  test("`${a ");
  test("`${a}` ");

  // Function calls

  test("f( ");
  test("f() ");
  test("f(); ");

  test("f(... ");
  test("f(...x ");
  test("f(...x) ");

  // Function constructors

  test_fun_arg("");
  test_fun_arg("a ");
  test_fun_arg("... ");
  test_fun_arg("...a ");

  // ==== Legacy ====

  // ==== asm.js ====

  test("(function() { 'use asm'; ");
  test("(function() { 'use asm'; var ");
  test("(function() { 'use asm'; var a ");
  test("(function() { 'use asm'; var a = ");
  test("(function() { 'use asm'; var a = 1 ");
  test("(function() { 'use asm'; var a = 1; ");
  test("(function() { 'use asm'; var a = 1; function ");
  test("(function() { 'use asm'; var a = 1; function f ");
  test("(function() { 'use asm'; var a = 1; function f( ");
  test("(function() { 'use asm'; var a = 1; function f() ");
  test("(function() { 'use asm'; var a = 1; function f() { ");
  test("(function() { 'use asm'; var a = 1; function f() { } ");
  test("(function() { 'use asm'; var a = 1; function f() { } var ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [ ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f] ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; } ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }) ");
  test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }); ");

  // ==== async/await ====

  // async/await function decralation

  test("async ");
  test("async function ");
  test("async function A ");
  test("async function A( ");
  test("async function A() ");
  test("async function A(a ");
  test("async function A(a) ");
  test("async function A(a) { ");
  test("async function A(a) {} ");
  test("async function A(a) { await ");
  test("async function A(a) { await X ");
  test("async function A(a) { await X; ");
  test("async function A(a) { await X; } ");
  test("async function A(a) { await await ");
  test("async function A(a) { await await await ");
  test("async function A(a) { await await await X ");
  test("async function A(a) { await await await X; ");
  test("async function A(a) { await await await X; } ");

  opts = { no_fun: true, no_eval: true, module: true };
  test("export default async ", opts);
  test("export default async function ", opts);
  test("export default async function ( ", opts);
  test("export default async function () ", opts);
  test("export default async function (a ", opts);
  test("export default async function (a) ", opts);
  test("export default async function (a) { ", opts);
  test("export default async function (a) {} ", opts);
  test("export default async function (a) { await ", opts);
  test("export default async function (a) { await X ", opts);
  test("export default async function (a) { await X; ", opts);
  test("export default async function (a) { await X; } ", opts);

  // async/await function expression

  test("(async ");
  test("(async function ");
  test("(async function A ");
  test("(async function A( ");
  test("(async function A() ");
  test("(async function A(a ");
  test("(async function A(a) ");
  test("(async function A(a) { ");
  test("(async function A(a) {} ");
  test("(async function A(a) { await ");
  test("(async function A(a) { await X ");
  test("(async function A(a) { await X; ");
  test("(async function A(a) { await X; } ");
  test("(async function A(a) { await X; }) ");

  test("(async function ( ");
  test("(async function () ");
  test("(async function (a ");
  test("(async function (a) ");
  test("(async function (a) { ");
  test("(async function (a) {} ");
  test("(async function (a) { await ");
  test("(async function (a) { await X ");
  test("(async function (a) { await X; ");
  test("(async function (a) { await X; } ");
  test("(async function (a) { await X; }) ");

  // async/await method

  test("({ async ");
  test("({ async m ");
  test("({ async m( ");
  test("({ async m() ");
  test("({ async m() { ");
  test("({ async m() {} ");
  test("({ async m() {}, ");

  test("class X { async ");
  test("class X { async m ");
  test("class X { async m( ");
  test("class X { async m() ");
  test("class X { async m() { ");
  test("class X { async m() {} ");

  test("class X { static async ");
  test("class X { static async m ");
  test("class X { static async m( ");
  test("class X { static async m() ");
  test("class X { static async m() { ");
  test("class X { static async m() {} ");

  // async/await arrow

  test("(async a ");
  test("(async a => ");
  test("(async a => b ");
  test("(async a => b) ");

  test("(async a => { ");
  test("(async a => { b ");
  test("(async a => { b } ");
  test("(async a => { b }) ");

  test("(async ( ");
  test("(async (a ");
  test("(async (a) ");
  test("(async (a) => ");
  test("(async (a) => b ");
  test("(async (a) => b) ");
  test("(async (a, ");
  test("(async (a, b ");
  test("(async (a, b) ");
  test("(async (a, b) => ");
  test("(async (a, b) => b ");
  test("(async (a, b) => b) ");

  test("(async ([ ");
  test("(async ([a ");
  test("(async ([a] ");
  test("(async ([a]) ");
  test("(async ([a]) => ");
  test("(async ([a]) => b ");
  test("(async ([a]) => b) ");
  test("(async ([a, ");
  test("(async ([a, b ");
  test("(async ([a, b] ");
  test("(async ([a, b]) ");
  test("(async ([a, b]) => ");
  test("(async ([a, b]) => b ");
  test("(async ([a, b]) => b) ");

  test("(async ({ ");
  test("(async ({a ");
  test("(async ({a} ");
  test("(async ({a}) ");
  test("(async ({a}) => ");
  test("(async ({a}) => b ");
  test("(async ({a}) => b) ");
  test("(async ({a, ");
  test("(async ({a, b ");
  test("(async ({a, b} ");
  test("(async ({a, b}) ");
  test("(async ({a, b}) => ");
  test("(async ({a, b}) => b ");
  test("(async ({a, b}) => b) ");
}

vs

function test_syntax(postfixes, check_error, ignore_opts) {
    function test_reflect(code, module) {
        var options = undefined;
        if (module) {
            options = {
                target: "module",
            };
        }
        for (postfix of postfixes) {
            var cur_code = code + postfix;

            var caught = false;

            try {
                Reflect.parse(cur_code, options);
            } catch (e) {
                caught = true;

                check_error(e, cur_code, "reflect");
            }

            assertEq(caught, true);
        }
    }
    function test_eval(code) {
        for (postfix of postfixes) {
            var cur_code = code + postfix;

            var caught = false;

            try {
                eval(cur_code);
            } catch (e) {
                caught = true;

                check_error(e, cur_code, "eval");
            }

            assertEq(caught, true);
        }
    }
    function test(code, opts = {    }) {
        if (ignore_opts) {
            opts = {            };
        }
        let no_strict = "no_strict" in opts && opts.no_strict;
        let no_fun = "no_fun" in opts && opts.no_fun;
        let no_eval = "no_eval" in opts && opts.no_eval;
        let module = "module" in opts && opts.module;
        test_reflect(code, module);
        if (!no_strict) {
            test_reflect("'use strict'; " + code, module);
        }
        if (!no_fun) {
            test_reflect("(function() { " + code, module);

            if (!no_strict) {
                test_reflect("(function() { 'use strict'; " + code, module);
            }
        }
        if (!no_eval) {
            test_eval(code);

            if (!no_strict) {
                test_eval("'use strict'; " + code);
            }

            if (!no_fun) {
                test_eval("(function() { " + code);

                if (!no_strict) {
                    test_eval("(function() { 'use strict'; " + code);
                }
            }
        }
    }
    function test_fun_arg(arg) {
        for (postfix of postfixes) {
            var cur_arg = arg + postfix;

            var caught = false;

            try {
                new Function(cur_arg, "");
            } catch (e) {
                caught = true;

                check_error(e, cur_arg, "fun_arg");
            }

            assertEq(caught, true);
        }
    }
    test("{ ");
    test("{ } ");
    test("{ 1 ");
    test("{ 1; ");
    test("{ 1; } ");
    test("a: for (;;) { break ");
    test("a: for (;;) { break; ");
    test("a: for (;;) { break a ");
    test("a: for (;;) { break a; ");
    test("a: for (;;) { break\n");
    test("a: for (;;) { continue ");
    test("a: for (;;) { continue; ");
    test("a: for (;;) { continue a ");
    test("a: for (;;) { continue a; ");
    test("a: for (;;) { continue\n");
    test("");
    test("; ");
    test("if ");
    test("if (");
    test("if (x ");
    test("if (x) ");
    test("if (x) { ");
    test("if (x) {} ");
    test("if (x) {} else ");
    test("if (x) {} else { ");
    test("if (x) {} else {} ");
    test("if (x) x ");
    test("if (x) x; ");
    test("if (x) x; else ");
    test("if (x) x; else y ");
    test("if (x) x; else y; ");
    test("switch ");
    test("switch (");
    test("switch (x ");
    test("switch (x) ");
    test("switch (x) { ");
    test("switch (x) { case ");
    test("switch (x) { case 1 ");
    test("switch (x) { case 1: ");
    test("switch (x) { case 1: case ");
    test("switch (x) { case 1: case 2 ");
    test("switch (x) { case 1: case 2: ");
    test("switch (x) { case 1: case 2: x ");
    test("switch (x) { case 1: case 2: x; ");
    test("switch (x) { case 1: case 2: x; break ");
    test("switch (x) { case 1: case 2: x; break; ");
    test("switch (x) { case 1: case 2: x; break; case ");
    test("switch (x) { case 1: case 2: x; break; case 3 ");
    test("switch (x) { case 1: case 2: x; break; case 3: y ");
    test("switch (x) { case 1: case 2: x; break; case 3: y; ");
    test("switch (x) { case 1: case 2: x; break; case 3: y; default ");
    test("switch (x) { case 1: case 2: x; break; case 3: y; default: ");
    test("switch (x) { case 1: case 2: x; break; case 3: y; default: z ");
    test("switch (x) { case 1: case 2: x; break; case 3: y; default: z; ");
    test("switch (x) { case 1: case 2: x; break; case 3: y; default: z; } ");
    test("throw ");
    test("throw x ");
    test("throw x; ");
    test("try ");
    test("try { ");
    test("try {} ");
    test("try {} catch ");
    test("try {} catch ( ");
    test("try {} catch (e ");
    test("try {} catch (e) ");
    test("try {} catch (e) { ");
    test("try {} catch (e) {} ");
    test("try {} catch (e) {} finally ");
    test("try {} catch (e) {} finally { ");
    test("try {} catch (e) {} finally {} ");
    test("var ");
    test("var x ");
    test("var x = ");
    test("var x = 1 ");
    test("var x = 1 + ");
    test("var x = 1 + 2 ");
    test("var x = 1 + 2, ");
    test("var x = 1 + 2, y ");
    test("var x = 1 + 2, y, ");
    test("var x = 1 + 2, y, z ");
    test("var x = 1 + 2, y, z; ");
    test("var [ ");
    test("var [ x ");
    test("var [ x, ");
    test("var [ x, ... ");
    test("var { ");
    test("var { x ");
    test("var { x: ");
    test("var { x: y ");
    test("var { x: y, ");
    test("var { x: y } ");
    test("var { x: y } = ");
    test("let ");
    test("let x ");
    test("let x = ");
    test("let x = 1 ");
    test("let x = 1 + ");
    test("let x = 1 + 2 ");
    test("let x = 1 + 2, ");
    test("let x = 1 + 2, y ");
    test("let x = 1 + 2, y, ");
    test("let x = 1 + 2, y, z ");
    test("let x = 1 + 2, y, z; ");
    test("let [ ");
    test("let [ x ");
    test("let [ x, ");
    test("let [ x, ... ");
    test("let { ");
    test("let { x ");
    test("let { x: ");
    test("let { x: y ");
    test("let { x: y, ");
    test("let { x: y } ");
    test("let { x: y } = ");
    test("const ");
    test("const x ");
    test("const x = ");
    test("const x = 1 ");
    test("const x = 1 + ");
    test("const x = 1 + 2 ");
    test("const x = 1 + 2, ");
    test("const x = 1 + 2, y = 0");
    test("const x = 1 + 2, y = 0, ");
    test("const x = 1 + 2, y = 0, z = 0 ");
    test("const x = 1 + 2, y = 0, z = 0; ");
    test("const [ ");
    test("const [ x ");
    test("const [ x, ");
    test("const [ x, ... ");
    test("const { ");
    test("const { x ");
    test("const { x: ");
    test("const { x: y ");
    test("const { x: y, ");
    test("const { x: y } ");
    test("const { x: y } = ");
    test("function ");
    test("function f ");
    test("function f( ");
    test("function f(x ");
    test("function f(x, ");
    test("function f(x, [ ");
    test("function f(x, [y ");
    test("function f(x, [y, ");
    test("function f(x, [y, { ");
    test("function f(x, [y, {z ");
    test("function f(x, [y, {z: ");
    test("function f(x, [y, {z: zz ");
    test("function f(x, [y, {z: zz,  ");
    test("function f(x, [y, {z: zz, w ");
    test("function f(x, [y, {z: zz, w} ");
    test("function f(x, [y, {z: zz, w}] ");
    test("function f(x, [y, {z: zz, w}], ");
    test("function f(x, [y, {z: zz, w}], v ");
    test("function f(x, [y, {z: zz, w}], v= ");
    test("function f(x, [y, {z: zz, w}], v=1 ");
    test("function f(x, [y, {z: zz, w}], v=1, ");
    test("function f(x, [y, {z: zz, w}], v=1, ... ");
    test("function f(x, [y, {z: zz, w}], v=1, ...t ");
    test("function f(x, [y, {z: zz, w}], v=1, ...t) ");
    test("function f(x, [y, {z: zz, w}], v=1, ...t) {");
    test("function f(x, [y, {z: zz, w}], v=1, ...t) { x ");
    test("function f(x, [y, {z: zz, w}], v=1, ...t) { x; ");
    test("function f(x, [y, {z: zz, w}], v=1, ...t) { x; } ");
    test("function* ");
    test("function* f ");
    test("function* f( ");
    test("function* f(x ");
    test("function* f(x, ");
    test("function* f(x, ... ");
    test("function* f(x, ...t ");
    test("function* f(x, ...t) ");
    test("function* f(x, ...t) {");
    test("function* f(x, ...t) { x ");
    test("function* f(x, ...t) { x; ");
    test("function* f(x, ...t) { x; } ");
    test("function f() { return ");
    test("function f() { return 1 ");
    test("function f() { return 1; ");
    test("function f() { return 1; } ");
    test("function f() { return; ");
    test("function f() { return\n");
    test("function* f() { yield ");
    test("function* f() { yield 1 ");
    test("function* f() { yield* ");
    test("function* f() { yield* 1 ");
    test("function* f() { yield\n");
    test("function* f() { yield*\n");
    test("do ");
    test("do {");
    test("do {} ");
    test("do {} while ");
    test("do {} while ( ");
    test("do {} while (x ");
    test("do {} while (x) ");
    test("do {} while (x); ");
    test("do x ");
    test("do x; ");
    test("do x; while ");
    test("for ");
    test("for (");
    test("for (x ");
    test("for (x; ");
    test("for (x; y ");
    test("for (x; y; ");
    test("for (x; y; z ");
    test("for (x; y; z) ");
    test("for (x; y; z) { ");
    test("for (x; y; z) {} ");
    test("for (x; y; z) x ");
    test("for (x; y; z) x; ");
    test("for (var ");
    test("for (var x ");
    test("for (var x = ");
    test("for (var x = y ");
    test("for (var x = y; ");
    test("for (let ");
    test("for (let x ");
    test("for (let x = ");
    test("for (let x = y ");
    test("for (let x = y; ");
    test("for (x in ");
    test("for (x in y ");
    test("for (x in y) ");
    test("for (var x in ");
    test("for (var x in y ");
    test("for (var x in y) ");
    test("for (let x in ");
    test("for (let x in y ");
    test("for (let x in y) ");
    test("for (x of ");
    test("for (x of y ");
    test("for (x of y) ");
    test("for (var x of ");
    test("for (var x of y ");
    test("for (var x of y) ");
    test("for (let x of ");
    test("for (let x of y ");
    test("for (let x of y) ");
    test("while ");
    test("while (");
    test("while (x ");
    test("while (x) ");
    test("while (x) { ");
    test("while (x) {} ");
    test("while (x) x ");
    test("while (x) x; ");
    test("debugger ");
    test("debugger; ");
    var opts = {
        no_fun: true,
        no_eval: true,
        module: true,
    };
    test("export ", opts);
    test("export { ", opts);
    test("export { x ", opts);
    test("export { x, ", opts);
    test("export { x, y ", opts);
    test("export { x, y as ", opts);
    test("export { x, y as z ", opts);
    test("export { x, y as z } ", opts);
    test("export { x, y as z } from ", opts);
    test("export { x, y as z } from 'a' ", opts);
    test("export { x, y as z } from 'a'; ", opts);
    test("export * ", opts);
    test("export * from ", opts);
    test("export * from 'a' ", opts);
    test("export * from 'a'; ", opts);
    test("export function ", opts);
    test("export function f ", opts);
    test("export function f( ", opts);
    test("export function f() ", opts);
    test("export function f() { ", opts);
    test("export function f() {} ", opts);
    test("export function f() {}; ", opts);
    test("export var ", opts);
    test("export var a ", opts);
    test("export var a = ", opts);
    test("export var a = 1 ", opts);
    test("export var a = 1, ", opts);
    test("export var a = 1, b ", opts);
    test("export var a = 1, b = ", opts);
    test("export var a = 1, b = 2 ", opts);
    test("export var a = 1, b = 2; ", opts);
    test("export let ", opts);
    test("export let a ", opts);
    test("export let a = ", opts);
    test("export let a = 1 ", opts);
    test("export let a = 1, ", opts);
    test("export let a = 1, b ", opts);
    test("export let a = 1, b = ", opts);
    test("export let a = 1, b = 2 ", opts);
    test("export let a = 1, b = 2; ", opts);
    test("export const ", opts);
    test("export const a ", opts);
    test("export const a = ", opts);
    test("export const a = 1 ", opts);
    test("export const a = 1, ", opts);
    test("export const a = 1, b ", opts);
    test("export const a = 1, b = ", opts);
    test("export const a = 1, b = 2 ", opts);
    test("export const a = 1, b = 2; ", opts);
    test("export class ", opts);
    test("export class Foo ", opts);
    test("export class Foo {  ", opts);
    test("export class Foo { constructor ", opts);
    test("export class Foo { constructor( ", opts);
    test("export class Foo { constructor() ", opts);
    test("export class Foo { constructor() { ", opts);
    test("export class Foo { constructor() {} ", opts);
    test("export class Foo { constructor() {} } ", opts);
    test("export class Foo { constructor() {} }; ", opts);
    test("export default ", opts);
    test("export default 1 ", opts);
    test("export default 1; ", opts);
    test("export default function ", opts);
    test("export default function() ", opts);
    test("export default function() { ", opts);
    test("export default function() {} ", opts);
    test("export default function() {}; ", opts);
    test("export default function foo ", opts);
    test("export default function foo( ", opts);
    test("export default function foo() ", opts);
    test("export default function foo() { ", opts);
    test("export default function foo() {} ", opts);
    test("export default function foo() {}; ", opts);
    test("export default class ", opts);
    test("export default class { ", opts);
    test("export default class { constructor ", opts);
    test("export default class { constructor( ", opts);
    test("export default class { constructor() ", opts);
    test("export default class { constructor() { ", opts);
    test("export default class { constructor() {} ", opts);
    test("export default class { constructor() {} } ", opts);
    test("export default class { constructor() {} }; ", opts);
    test("export default class Foo ", opts);
    test("export default class Foo { ", opts);
    test("export default class Foo { constructor ", opts);
    test("export default class Foo { constructor( ", opts);
    test("export default class Foo { constructor() ", opts);
    test("export default class Foo { constructor() { ", opts);
    test("export default class Foo { constructor() {} ", opts);
    test("export default class Foo { constructor() {} } ", opts);
    test("export default class Foo { constructor() {} }; ", opts);
    test("import ", opts);
    test("import x ", opts);
    test("import x from ", opts);
    test("import x from 'a' ", opts);
    test("import x from 'a'; ", opts);
    test("import { ", opts);
    test("import { x ", opts);
    test("import { x, ", opts);
    test("import { x, y ", opts);
    test("import { x, y } ", opts);
    test("import { x, y } from ", opts);
    test("import { x, y } from 'a' ", opts);
    test("import { x, y } from 'a'; ", opts);
    test("import { x as ", opts);
    test("import { x as y ", opts);
    test("import { x as y } ", opts);
    test("import { x as y } from ", opts);
    test("import { x as y } from 'a' ", opts);
    test("import { x as y } from 'a'; ", opts);
    test("import 'a' ", opts);
    test("import 'a'; ", opts);
    test("import * ", opts);
    test("import * as ", opts);
    test("import * as a ", opts);
    test("import * as a from ", opts);
    test("import * as a from 'a' ", opts);
    test("import * as a from 'a'; ", opts);
    test("import a ", opts);
    test("import a, ", opts);
    test("import a, * ", opts);
    test("import a, * as ", opts);
    test("import a, * as b ", opts);
    test("import a, * as b from ", opts);
    test("import a, * as b from 'c' ", opts);
    test("import a, * as b from 'c'; ", opts);
    test("import a, { ", opts);
    test("import a, { b ", opts);
    test("import a, { b } ", opts);
    test("import a, { b } from ", opts);
    test("import a, { b } from 'c' ", opts);
    test("import a, { b } from 'c'; ", opts);
    test("a ");
    test("a: ");
    opts = {
        no_strict: true,
    };
    test("with ", opts);
    test("with (", opts);
    test("with (x ", opts);
    test("with (x) ", opts);
    test("with (x) { ", opts);
    test("with (x) {} ", opts);
    test("with (x) x ", opts);
    test("with (x) x; ", opts);
    test("this ");
    test("(function ");
    test("(function ( ");
    test("(function (x ");
    test("(function (x, ");
    test("(function (x, ... ");
    test("(function (x, ...t ");
    test("(function (x, ...t) ");
    test("(function (x, ...t) {");
    test("(function (x, ...t) { x ");
    test("(function (x, ...t) { x; ");
    test("(function (x, ...t) { x; } ");
    test("(function (x, ...t) { x; }) ");
    test("(function* ");
    test("(function* ( ");
    test("(function* (x ");
    test("(function* (x, ");
    test("(function* (x, ... ");
    test("(function* (x, ...t ");
    test("(function* (x, ...t) ");
    test("(function* (x, ...t) {");
    test("(function* (x, ...t) { x ");
    test("(function* (x, ...t) { x; ");
    test("(function* (x, ...t) { x; } ");
    test("(function* (x, ...t) { x; }) ");
    test("[ ");
    test("[] ");
    test("[1 ");
    test("[1, ");
    test("[1, ... ");
    test("[1, ...x ");
    test("[1, ...x] ");
    test("({ ");
    test("({ x ");
    test("({ x: ");
    test("({ x: 1 ");
    test("({ x: 1, ");
    test("({ x: 1, y ");
    test("({ x: 1, y: ");
    test("({ x: 1, y: 2 ");
    test("({ x: 1, y: 2, ");
    test("({ x: 1, y: 2, z ");
    test("({ x: 1, y: 2, z, ");
    test("({ x: 1, y: 2, z, w ");
    test("({ x: 1, y: 2, z, w } ");
    test("({ x: 1, y: 2, z, w }) ");
    test("({ [");
    test("({ [k ");
    test("({ [k] ");
    test("({ [k]: ");
    test("({ [k]: 1 ");
    test("({ [k]: 1, ");
    test("({ get ");
    test("({ get p ");
    test("({ get p( ");
    test("({ get p() ");
    test("({ get p() { ");
    test("({ get p() {} ");
    test("({ get p() {}, ");
    test("({ get p() {}, } ");
    test("({ get [ ");
    test("({ get [p ");
    test("({ get [p] ");
    test("({ get [p]( ");
    test("({ get [p]() ");
    test("({ set ");
    test("({ set p ");
    test("({ set p( ");
    test("({ set p(v ");
    test("({ set p(v) ");
    test("({ set p(v) { ");
    test("({ set p(v) {} ");
    test("({ set [ ");
    test("({ set [p ");
    test("({ set [p] ");
    test("({ set [p]( ");
    test("({ set [p](v ");
    test("({ set [p](v) ");
    test("({ m ");
    test("({ m( ");
    test("({ m() ");
    test("({ m() { ");
    test("({ m() {} ");
    test("({ m() {}, ");
    test("({ [ ");
    test("({ [m ");
    test("({ [m] ");
    test("({ [m]( ");
    test("({ [m]() ");
    test("({ [m]() { ");
    test("({ [m]() {} ");
    test("({ [m]() {}, ");
    test("({ * ");
    test("({ *m ");
    test("({ *m( ");
    test("({ *m() ");
    test("({ *m() { ");
    test("({ *m() {} ");
    test("({ *m() {}, ");
    test("({ *[ ");
    test("({ *[m ");
    test("({ *[m] ");
    test("({ *[m]( ");
    test("({ *[m]() ");
    test("({ *[m]() { ");
    test("({ *[m]() {} ");
    test("({ *[m]() {}, ");
    test("({ * get ");
    test("({ * get ( ");
    test("({ * get () ");
    test("({ * get () { ");
    test("({ * get () {} ");
    test("({ * get () {}, ");
    test("({ * set ");
    test("({ * set ( ");
    test("({ * set () ");
    test("({ * set () { ");
    test("({ * set () {} ");
    test("({ * set () {}, ");
    test("/a/ ");
    test("/a/g ");
    test("a[ ");
    test("a[1 ");
    test("a[1] ");
    test("a. ");
    test("a.b ");
    test("a.b; ");
    test("new ");
    test("new f ");
    test("new f( ");
    test("new f() ");
    test("new f(); ");
    test("a ++ ");
    test("a ++; ");
    test("-- ");
    test("-- a ");
    test("-- a; ");
    test("delete ");
    test("delete a ");
    test("delete a[ ");
    test("delete a[b ");
    test("delete a[b] ");
    test("delete a[b]; ");
    test("delete ( ");
    test("delete (a ");
    test("delete (a[ ");
    test("delete (a[b ");
    test("delete (a[b] ");
    test("delete (a[b]) ");
    test("delete (a[b]); ");
    test("void ");
    test("void a ");
    test("void a; ");
    test("void (");
    test("void (a ");
    test("void (a) ");
    test("void (a); ");
    test("typeof ");
    test("typeof a ");
    test("typeof a; ");
    test("typeof (");
    test("typeof (a ");
    test("typeof (a) ");
    test("typeof (a); ");
    test("- ");
    test("- 1 ");
    test("- 1; ");
    test("+ ");
    test("+ 1 ");
    test("+ 1; ");
    test("1 + ");
    test("1 + 1 ");
    test("1 + 1; ");
    test("a in ");
    test("a in b ");
    test("a in b; ");
    test("a instanceof ");
    test("a instanceof b ");
    test("a instanceof b; ");
    test("1 == ");
    test("1 == 1 ");
    test("1 == 1; ");
    test("1 << ");
    test("1 << 1 ");
    test("1 << 1; ");
    test("1 & ");
    test("1 & 1 ");
    test("1 & 1; ");
    test("1 || ");
    test("1 || 1 ");
    test("1 || 1; ");
    test("1 ? ");
    test("1 ? 2 ");
    test("1 ? 2 : ");
    test("1 ? 2 : 3 ");
    test("1 ? 2 : 3; ");
    test("x = ");
    test("x = 1 ");
    test("x = 1 + ");
    test("x = 1 + 2 ");
    test("x = 1 + 2; ");
    test("1, ");
    test("1, 2 ");
    test("1, 2; ");
    test("a => ");
    test("a => 1 ");
    test("a => 1; ");
    test("a => { ");
    test("a => {} ");
    test("a => {}; ");
    test("( ");
    test("() ");
    test("() => ");
    test("(...");
    test("(...a ");
    test("(...a) ");
    test("(...a) => ");
    test("([ ");
    test("([a ");
    test("([a] ");
    test("([a]) ");
    test("([a]) => ");
    test("({ ");
    test("({a ");
    test("({a} ");
    test("({a}) ");
    test("({a}) => ");
    test("({a: ");
    test("({a: b ");
    test("({a: b, ");
    test("({a: b} ");
    test("({a: b}) ");
    test("({a: b}) => ");
    test("class ");
    test("class a ");
    test("class a { ");
    test("class a { constructor ");
    test("class a { constructor( ");
    test("class a { constructor() ");
    test("class a { constructor() { ");
    test("class a { constructor() { } ");
    test("class a { constructor() { } } ");
    test("class a { constructor() { } static ");
    test("class a { constructor() { } static m ");
    test("class a { constructor() { } static m( ");
    test("class a { constructor() { } static m() ");
    test("class a { constructor() { } static m() { ");
    test("class a { constructor() { } static m() {} ");
    test("class a { constructor() { } static m() {} } ");
    test("class a { constructor() { } static ( ");
    test("class a { constructor() { } static () ");
    test("class a { constructor() { } static () { ");
    test("class a { constructor() { } static () {} ");
    test("class a { constructor() { } static () {} } ");
    test("class a { constructor() { } static get ");
    test("class a { constructor() { } static get p ");
    test("class a { constructor() { } static get p( ");
    test("class a { constructor() { } static get p() ");
    test("class a { constructor() { } static get p() { ");
    test("class a { constructor() { } static get p() {} ");
    test("class a { constructor() { } static get p() {} } ");
    test("class a { constructor() { } static set ");
    test("class a { constructor() { } static set p ");
    test("class a { constructor() { } static set p( ");
    test("class a { constructor() { } static set p(v ");
    test("class a { constructor() { } static set p(v) ");
    test("class a { constructor() { } static set p(v) { ");
    test("class a { constructor() { } static set p(v) {} ");
    test("class a { constructor() { } static set p(v) {} } ");
    test("class a { constructor() { } * ");
    test("class a { constructor() { } *m ");
    test("class a { constructor() { } *m( ");
    test("class a { constructor() { } *m() ");
    test("class a { constructor() { } *m() { ");
    test("class a { constructor() { } *m() {} ");
    test("class a { constructor() { } *m() {} } ");
    test("class a { constructor() { } static * ");
    test("class a { constructor() { } static *m ");
    test("class a { constructor() { } static *m( ");
    test("class a { constructor() { } static *m() ");
    test("class a { constructor() { } static *m() { ");
    test("class a { constructor() { } static *m() {} ");
    test("class a { constructor() { } static *m() {} } ");
    test("class a extends ");
    test("class a extends b ");
    test("class a extends b { ");
    test("class a extends ( ");
    test("class a extends ( b ");
    test("class a extends ( b ) ");
    test("class a extends ( b ) { ");
    test("( class ");
    test("( class a ");
    test("( class a { ");
    test("( class a { constructor ");
    test("( class a { constructor( ");
    test("( class a { constructor() ");
    test("( class a { constructor() { ");
    test("( class a { constructor() { } ");
    test("( class a { constructor() { } } ");
    test("( class a { constructor() { } } ) ");
    test("(class a extends ");
    test("(class a extends b ");
    test("(class a extends b { ");
    test("(class a extends ( ");
    test("(class a extends ( b ");
    test("(class a extends ( b ) ");
    test("(class a extends ( b ) { ");
    test("( class { ");
    test("( class { constructor ");
    test("( class { constructor( ");
    test("( class { constructor() ");
    test("( class { constructor() { ");
    test("( class { constructor() { } ");
    test("( class { constructor() { } } ");
    test("( class { constructor() { } } ) ");
    test("(class extends ");
    test("(class extends b ");
    test("(class extends b { ");
    test("(class extends ( ");
    test("(class extends ( b ");
    test("(class extends ( b ) ");
    test("(class extends ( b ) { ");
    test("a ");
    test("1 ");
    test("1. ");
    test("1.2 ");
    test("true ");
    test("false ");
    test("\"a\" ");
    test("'a' ");
    test("null ");
    test("`${ ");
    test("`${a ");
    test("`${a}` ");
    test("f( ");
    test("f() ");
    test("f(); ");
    test("f(... ");
    test("f(...x ");
    test("f(...x) ");
    test_fun_arg("");
    test_fun_arg("a ");
    test_fun_arg("... ");
    test_fun_arg("...a ");
    test("(function() { 'use asm'; ");
    test("(function() { 'use asm'; var ");
    test("(function() { 'use asm'; var a ");
    test("(function() { 'use asm'; var a = ");
    test("(function() { 'use asm'; var a = 1 ");
    test("(function() { 'use asm'; var a = 1; ");
    test("(function() { 'use asm'; var a = 1; function ");
    test("(function() { 'use asm'; var a = 1; function f ");
    test("(function() { 'use asm'; var a = 1; function f( ");
    test("(function() { 'use asm'; var a = 1; function f() ");
    test("(function() { 'use asm'; var a = 1; function f() { ");
    test("(function() { 'use asm'; var a = 1; function f() { } ");
    test("(function() { 'use asm'; var a = 1; function f() { } var ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [ ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f] ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; } ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }) ");
    test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }); ");
    test("async ");
    test("async function ");
    test("async function A ");
    test("async function A( ");
    test("async function A() ");
    test("async function A(a ");
    test("async function A(a) ");
    test("async function A(a) { ");
    test("async function A(a) {} ");
    test("async function A(a) { await ");
    test("async function A(a) { await X ");
    test("async function A(a) { await X; ");
    test("async function A(a) { await X; } ");
    test("async function A(a) { await await ");
    test("async function A(a) { await await await ");
    test("async function A(a) { await await await X ");
    test("async function A(a) { await await await X; ");
    test("async function A(a) { await await await X; } ");
    opts = {
        no_fun: true,
        no_eval: true,
        module: true,
    };
    test("export default async ", opts);
    test("export default async function ", opts);
    test("export default async function ( ", opts);
    test("export default async function () ", opts);
    test("export default async function (a ", opts);
    test("export default async function (a) ", opts);
    test("export default async function (a) { ", opts);
    test("export default async function (a) {} ", opts);
    test("export default async function (a) { await ", opts);
    test("export default async function (a) { await X ", opts);
    test("export default async function (a) { await X; ", opts);
    test("export default async function (a) { await X; } ", opts);
    test("(async ");
    test("(async function ");
    test("(async function A ");
    test("(async function A( ");
    test("(async function A() ");
    test("(async function A(a ");
    test("(async function A(a) ");
    test("(async function A(a) { ");
    test("(async function A(a) {} ");
    test("(async function A(a) { await ");
    test("(async function A(a) { await X ");
    test("(async function A(a) { await X; ");
    test("(async function A(a) { await X; } ");
    test("(async function A(a) { await X; }) ");
    test("(async function ( ");
    test("(async function () ");
    test("(async function (a ");
    test("(async function (a) ");
    test("(async function (a) { ");
    test("(async function (a) {} ");
    test("(async function (a) { await ");
    test("(async function (a) { await X ");
    test("(async function (a) { await X; ");
    test("(async function (a) { await X; } ");
    test("(async function (a) { await X; }) ");
    test("({ async ");
    test("({ async m ");
    test("({ async m( ");
    test("({ async m() ");
    test("({ async m() { ");
    test("({ async m() {} ");
    test("({ async m() {}, ");
    test("class X { async ");
    test("class X { async m ");
    test("class X { async m( ");
    test("class X { async m() ");
    test("class X { async m() { ");
    test("class X { async m() {} ");
    test("class X { static async ");
    test("class X { static async m ");
    test("class X { static async m( ");
    test("class X { static async m() ");
    test("class X { static async m() { ");
    test("class X { static async m() {} ");
    test("(async a ");
    test("(async a => ");
    test("(async a => b ");
    test("(async a => b) ");
    test("(async a => { ");
    test("(async a => { b ");
    test("(async a => { b } ");
    test("(async a => { b }) ");
    test("(async ( ");
    test("(async (a ");
    test("(async (a) ");
    test("(async (a) => ");
    test("(async (a) => b ");
    test("(async (a) => b) ");
    test("(async (a, ");
    test("(async (a, b ");
    test("(async (a, b) ");
    test("(async (a, b) => ");
    test("(async (a, b) => b ");
    test("(async (a, b) => b) ");
    test("(async ([ ");
    test("(async ([a ");
    test("(async ([a] ");
    test("(async ([a]) ");
    test("(async ([a]) => ");
    test("(async ([a]) => b ");
    test("(async ([a]) => b) ");
    test("(async ([a, ");
    test("(async ([a, b ");
    test("(async ([a, b] ");
    test("(async ([a, b]) ");
    test("(async ([a, b]) => ");
    test("(async ([a, b]) => b ");
    test("(async ([a, b]) => b) ");
    test("(async ({ ");
    test("(async ({a ");
    test("(async ({a} ");
    test("(async ({a}) ");
    test("(async ({a}) => ");
    test("(async ({a}) => b ");
    test("(async ({a}) => b) ");
    test("(async ({a, ");
    test("(async ({a, b ");
    test("(async ({a, b} ");
    test("(async ({a, b}) ");
    test("(async ({a, b}) => ");
    test("(async ({a, b}) => b ");
    test("(async ({a, b}) => b) ");
}
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

setJitCompilerOption("ion.warmup.trigger", 30);

var PointType = TypedObject.uint32.array(3);
var VecPointType = PointType.array(3);

function foo() {
  for (var i = 0; i < 5000; i += 10) {
    var vec = new VecPointType();

    var i0 = i % 3;
    var i1 = (i+1) % 3;
    var i2 = (i+2) % 3;

    vec[i0][i0] = i;
    vec[i0][i1] = i+1;
    vec[i0][i2] = i+2;

    vec[i1][i0] = i+3;
    vec[i1][i1] = i+4;
    vec[i1][i2] = i+5;

    vec[i2][i0] = i+6;
    vec[i2][i1] = i+7;
    vec[i2][i2] = i+8;

    var sum = vec[i0][i0] + vec[i0][i1] + vec[i0][i2];
    assertEq(sum, 3*i + 3);
    sum = vec[i1][i0] + vec[i1][i1] + vec[i1][i2];
    assertEq(sum, 3*i + 12);
    sum = vec[i2][i0] + vec[i2][i1] + vec[i2][i2];
    assertEq(sum, 3*i + 21);
  }
}

foo();

vs

setJitCompilerOption("ion.warmup.trigger", 30);

var PointType = TypedObject.uint32.array(3);

var VecPointType = PointType.array(3);

function foo() {
    for (let i = 0;i < 5000;i += 10) {
        var vec = new VecPointType();

        var i0 = i % 3;

        var i1 = i + 1 % 3;

        var i2 = i + 2 % 3;

        vec[i0][i0] = i;

        vec[i0][i1] = i + 1;

        vec[i0][i2] = i + 2;

        vec[i1][i0] = i + 3;

        vec[i1][i1] = i + 4;

        vec[i1][i2] = i + 5;

        vec[i2][i0] = i + 6;

        vec[i2][i1] = i + 7;

        vec[i2][i2] = i + 8;

        var sum = vec[i0][i0] + vec[i0][i1] + vec[i0][i2];

        assertEq(sum, 3 * i + 3);

        sum = vec[i1][i0] + vec[i1][i1] + vec[i1][i2];

        assertEq(sum, 3 * i + 12);

        sum = vec[i2][i0] + vec[i2][i1] + vec[i2][i2];

        assertEq(sum, 3 * i + 21);
    }
}

foo();
// Return the trap result
var proto = Object.create(null, {
    'foo': {
        configurable: true
    }
});
var target = Object.create(proto, {
    'bar': {
        configurable: true
    }
});

var handler = { has: () => false };

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    assertEq('foo' in p, false);
    assertEq('bar' in p, false);
}

vs

var proto = Object.create(null, ({
    'foo': ({
        configurable: true,
    }),
}));

var target = Object.create(proto, ({
    'bar': ({
        configurable: true,
    }),
}));

var handler = ({
    has: ()  => false,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    assertEq('foo' in p, false);

    assertEq('bar' in p, false);
}
/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */

// An offset A of a script should have successor B iff B has predecessor A.
// Offsets reached while stepping through a script should be successors of
// each other.

var scripts = [
  "n = 1",
  "if (n == 0) return; else n = 2",
  "while (n < 5) n++",
  "switch (n) { case 4: break; case 5: return 0; }",
];

var g = newGlobal();
for (var n in scripts) {
  g.eval("function f" + n + "() { " + scripts[n] + " }");
}

var dbg = Debugger(g);
dbg.onDebuggerStatement = function (frame) {
  for (var n in scripts) {
    var compares = 0;
    var script = frame.eval("f" + n).return.script;
    var worklist = [script.mainOffset];
    var seen = [];
    while (worklist.length) {
      var offset = worklist.pop();
      if (seen.includes(offset))
        continue;
      seen.push(offset);
      var succs = script.getSuccessorOffsets(offset);
      for (var succ of succs) {
        compares++;
        var preds = script.getPredecessorOffsets(succ);
        assertEq(preds.includes(offset), true);
        worklist.push(succ);
      }
    }
    assertEq(compares != 0, true);
    compares = 0;
    for (var offset of seen) {
      var preds = script.getPredecessorOffsets(offset);
      for (var pred of preds) {
        var succs = script.getSuccessorOffsets(pred);
        compares++;
        assertEq(succs.includes(offset), true);
      }
    }
    assertEq(compares != 0, true);
    script.setBreakpoint(script.mainOffset, { hit: mainBreakpointHandler });
  }
};
g.eval("debugger");

function mainBreakpointHandler(frame) {
  frame.lastOffset = frame.script.mainOffset;
  frame.onStep = onStepHandler;
}

function onStepHandler() {
  steps++;
  var succs = this.script.getSuccessorOffsets(this.lastOffset);
  if (!succs.includes(this.offset)) {
    // The onStep handler might skip over opcodes, even when running in the
    // interpreter. Check transitive successors of the last offset.
    var found = false;
    for (var succ of succs) {
      if (this.script.getSuccessorOffsets(succ).includes(this.offset))
        found = true;
    }
    assertEq(found, true);
  }
  this.lastOffset = this.offset;
}

for (var n in scripts) {
  var steps = 0;
  g.eval("f" + n + "()");
  assertEq(steps != 0, true);
}

vs

var scripts = ["n = 1", "if (n == 0) return; else n = 2", "while (n < 5) n++", "switch (n) { case 4: break; case 5: return 0; }",];

var g = newGlobal();

for (n in scripts) {
    g.eval("function f" + n + "() { " + scripts[n] + " }");
}

var dbg = Debugger(g);

dbg.onDebuggerStatement = (function(frame) {
    for (n in scripts) {
        var compares = 0;

        var script = frame.eval("f" + n).return.script;

        var worklist = [script.mainOffset,];

        var seen = [];

        while (worklist.length) {
            var offset = worklist.pop();

            if (seen.includes(offset)) continue;


            seen.push(offset);

            var succs = script.getSuccessorOffsets(offset);

            for (succ of succs) {
                compares++;

                var preds = script.getPredecessorOffsets(succ);

                assertEq(preds.includes(offset), true);

                worklist.push(succ);
            }
        }

        assertEq(compares != 0, true);

        compares = 0;

        for (offset of seen) {
            var preds = script.getPredecessorOffsets(offset);

            for (pred of preds) {
                var succs = script.getSuccessorOffsets(pred);

                compares++;

                assertEq(succs.includes(offset), true);
            }
        }

        assertEq(compares != 0, true);

        script.setBreakpoint(script.mainOffset, {
            hit: mainBreakpointHandler,
        });
    }
});

g.eval("debugger");

function mainBreakpointHandler(frame) {
    frame.lastOffset = frame.script.mainOffset;
    frame.onStep = onStepHandler;
}

function onStepHandler() {
    steps++;
    var succs = this.script.getSuccessorOffsets(this.lastOffset);
    if (!succs.includes(this.offset)) {
        var found = false;

        for (succ of succs) {
            if (this.script.getSuccessorOffsets(succ).includes(this.offset)) found = true;

        }

        assertEq(found, true);
    }
    this.lastOffset = this.offset;
}

for (n in scripts) {
    var steps = 0;

    g.eval("f" + n + "()");

    assertEq(steps != 0, true);
}
// Errors adding globals in addAllGlobalsAsDebuggees should be reported.

// The exception that might be thrown in this test reflects our inability
// to change compartments to debug mode while they have frames on the
// stack. If we run this test with --debugjit, it won't throw an error at
// all, since all compartments are already in debug mode. So, pass if the
// script completes normally, or throws an appropriate exception.
try {
  newGlobal().eval("(new Debugger).addAllGlobalsAsDebuggees();");
} catch (ex) {
  assertEq(!!(''+ex).match(/can't start debugging: a debuggee script is on the stack/), true);
}

vs

try {
    newGlobal().eval("(new Debugger).addAllGlobalsAsDebuggees();");
} catch (ex) {
    assertEq(!!'' + ex.match(/can't start debugging: a debuggee script is on the stack/), true);
}
// Return the names returned by the trap
var target = {};
Object.defineProperty(target, 'foo', {
    configurable: true
});

var handler = { ownKeys: () => [ 'bar' ] };

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    var names = Object.getOwnPropertyNames(p);
    assertEq(names.length, 1);
    assertEq(names[0], 'bar');
}

var protoWithAB = Object.create(null, {
    a: {
        enumerable: true,
        configurable: true
    },
    b: {
        enumerable: false,
        configurable: true
    }
});
var objWithCD = Object.create(protoWithAB, {
    c: {
        enumerable: true,
        configurable: true
    },
    d: {
        enumerable: true,
        configurable: true
    }
});

handler = { ownKeys: () => [ 'c', 'e' ] };
for (let p of [new Proxy(objWithCD, handler), Proxy.revocable(objWithCD, handler).proxy]) {
    var names = Object.getOwnPropertyNames(p);
    assertEq(names.length, 2);
    assertEq(names[0], 'c');
    assertEq(names[1], 'e');
}

vs

var target = ({});

Object.defineProperty(target, 'foo', ({
    configurable: true,
}));

var handler = ({
    ownKeys: ()  => ['bar',],
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    var names = Object.getOwnPropertyNames(p);

    assertEq(names.length, 1);

    assertEq(names[0], 'bar');
}

var protoWithAB = Object.create(null, ({
    a: ({
        enumerable: true,
        configurable: true,
    }),
    b: ({
        enumerable: false,
        configurable: true,
    }),
}));

var objWithCD = Object.create(protoWithAB, ({
    c: ({
        enumerable: true,
        configurable: true,
    }),
    d: ({
        enumerable: true,
        configurable: true,
    }),
}));

handler = ({
    ownKeys: ()  => ['c', 'e',],
});

for (p of [new Proxy(objWithCD, handler), Proxy.revocable(objWithCD, handler).proxy,]) {
    var names = Object.getOwnPropertyNames(p);

    assertEq(names.length, 2);

    assertEq(names[0], 'c');

    assertEq(names[1], 'e');
}
var g = newGlobal();
var dbg = new Debugger(g);
g.eval("" + function f(c) {
  if (c == 0)
    return;
  if (c == 2)
    debugger;
  f(c-1);
  for (var i = 0; i < 100; i++)
    Debugger += newGlobal('#15: myObj.parseFloat !== parseFloat');
});
dbg.onDebuggerStatement = function (frame) {};
g.eval("f(2)");

vs

var g = newGlobal();

var dbg = new Debugger(g);

g.eval("" + (function f(c) {
    if (c == 0) return;

    if (c == 2) debugger;;

    f(c - 1);
    for (let i = 0;i < 100;i++) Debugger += newGlobal('#15: myObj.parseFloat !== parseFloat');
}));

dbg.onDebuggerStatement = (function(frame) { });

g.eval("f(2)");
// Test the behavior of property sets on typed objects when they are a
// prototype or their prototype has a setter.
var TO = TypedObject;

function assertThrows(fun, errorType) {
  try {
    fun();
    assertEq(true, false, "Expected error, but none was thrown");
  } catch (e) {
    assertEq(e instanceof errorType, true, "Wrong error type thrown");
  }
}

var PointType = new TO.StructType({x: TO.int32, y: TO.int32 });

function testPoint() {
    var p = new PointType();
    var sub = Object.create(p);
    var found;
    Object.defineProperty(PointType.prototype, "z", {set: function(a) { this.d = a; }});
    Object.defineProperty(PointType.prototype, "innocuous", {set: function(a) { found = a; }});

    sub.x = 5;
    assertEq(sub.x, 5);
    assertEq(p.x, 0);

    sub.z = 5;
    assertEq(sub.d, 5);
    assertEq(sub.z, undefined);

    sub[3] = 5;
    assertEq(sub[3], 5);

    p.innocuous = 10;
    assertEq(found, 10);

    assertThrows(function() {
        p.z = 10;
        assertEq(true, false);
    }, TypeError);
}
testPoint();

var IntArrayType = new TO.ArrayType(TO.int32, 3);

function testArray() {
    var arr = new IntArrayType();
    var found;
    Object.defineProperty(IntArrayType.prototype, 5, {set: function(a) { found = a; }});

    assertThrows(function() {
        arr[5] = 5;
    }, RangeError);

    assertThrows(function() {
        arr[4] = 5;
    }, RangeError);

    var p = Object.create(arr);
    p.length = 100;
    assertEq(p.length, 3);

    assertThrows(function() {
        "use strict";
        p.length = 100;
    }, TypeError);
}
testArray();

vs

var TO = TypedObject;

function assertThrows(fun, errorType) {
    try {
        fun();

        assertEq(true, false, "Expected error, but none was thrown");
    } catch (e) {
        assertEq(e instanceof errorType, true, "Wrong error type thrown");
    }
}

var PointType = new TO.StructType(({
    x: TO.int32,
    y: TO.int32,
}));

function testPoint() {
    var p = new PointType();
    var sub = Object.create(p);
    var found;
    Object.defineProperty(PointType.prototype, "z", {
        set: function(a) {
            this.d = a;
        },
    });
    Object.defineProperty(PointType.prototype, "innocuous", {
        set: function(a) {
            found = a;
        },
    });
    sub.x = 5;
    assertEq(sub.x, 5);
    assertEq(p.x, 0);
    sub.z = 5;
    assertEq(sub.d, 5);
    assertEq(sub.z, undefined);
    sub[3] = 5;
    assertEq(sub[3], 5);
    p.innocuous = 10;
    assertEq(found, 10);
    assertThrows(function() {
        p.z = 10;
        assertEq(true, false);
    }, TypeError);
}

testPoint();

var IntArrayType = new TO.ArrayType(TO.int32, 3);

function testArray() {
    var arr = new IntArrayType();
    var found;
    Object.defineProperty(IntArrayType.prototype, 5, {
        set: function(a) {
            found = a;
        },
    });
    assertThrows(function() {
        arr[5] = 5;
    }, RangeError);
    assertThrows(function() {
        arr[4] = 5;
    }, RangeError);
    var p = Object.create(arr);
    p.length = 100;
    assertEq(p.length, 3);
    assertThrows(function() {
        'use strict';
        p.length = 100;
    }, TypeError);
}

testArray();
// Tests that we can reflect optimized out values.
//
// Unfortunately these tests are brittle. They depend on opaque JIT heuristics
// kicking in.

// Use gczeal 0 to keep CGC from invalidating Ion code and causing test failures.
gczeal(0);

load(libdir + "jitopts.js");

if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
  quit(0);

withJitOptions(Opts_Ion2NoOffthreadCompilation, function () {
  var g = newGlobal();
  var dbg = new Debugger;

  // Note that this *depends* on CCW scripted functions being opaque to Ion
  // optimization and not deoptimizing the frames below the call to toggle.
  g.toggle = function toggle(d) {
    if (d) {
      dbg.addDebuggee(g);
      var frame = dbg.getNewestFrame();
      assertEq(frame.implementation, "ion");
      // x is unused and should be elided.
      assertEq(frame.environment.getVariable("x").optimizedOut, true);
      assertEq(frame.arguments[1].optimizedOut, true);
    }
  };

  g.eval("" + function f(d, x) {
    "use strict";
    eval("g(d, x)"); // `eval` to avoid inlining g.
  });

  g.eval("" + function g(d, x) {
    "use strict";
    for (var i = 0; i < 200; i++);
    toggle(d);
  });

  g.eval("(" + function test() {
    for (i = 0; i < 5; i++)
      f(false, 42);
    f(true, 42);
  } + ")();");
});

vs

gczeal(0);

load(libdir + "jitopts.js");

if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation)) quit(0);


withJitOptions(Opts_Ion2NoOffthreadCompilation, (function() {
    var g = newGlobal();
    var dbg = new Debugger();
    g.toggle = function toggle(d) {
        if (d) {
            dbg.addDebuggee(g);

            var frame = dbg.getNewestFrame();

            assertEq(frame.implementation, "ion");

            assertEq(frame.environment.getVariable("x").optimizedOut, true);

            assertEq(frame.arguments[1].optimizedOut, true);
        }
    };
    g.eval("" + function f(d, x) {
        'use strict';
        eval("g(d, x)");
    });
    g.eval("" + function g(d, x) {
        'use strict';
        for (let i = 0;i < 200;i++) ;
        toggle(d);
    });
    g.eval("(" + function test() {
        for (i = 0;i < 5;i++) f(false, 42);
        f(true, 42);
    } + ")();");
}));
load(libdir + "asserts.js");

// Throw a TypeError if the trap skips a non-configurable property
var target = {};
Object.defineProperty(target, 'foo', {
    configurable: false
});

var handler = { ownKeys: () => [] };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    configurable: false,
}));

var handler = ({
    ownKeys: ()  => [],
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyNames(p), TypeError);
var array = new (TypedObject.uint8.array(5));

for (var i = 0; i < array.length; i++)
    assertEq(i in array, true);

for (var v of [20, 300, -1, 5, -10, Math.pow(2, 32) - 1, -Math.pow(2, 32)])
    assertEq(v in array, false);

// Don't inherit elements
array.__proto__[50] = "hello";
assertEq(array.__proto__[50], "hello");
assertEq(50 in array, false);

// Do inherit normal properties
array.__proto__.a = "world";
assertEq(array.__proto__.a, "world");
assertEq("a" in array, true);

vs

var array = new TypedObject.uint8.array(5)();

for (let i = 0;i < array.length;i++) assertEq(i in array, true);

for (v of [20, 300, -1, 5, -10, Math.pow(2, 32) - 1, -Math.pow(2, 32),]) assertEq(v in array, false);

array.__proto__[50] = "hello";

assertEq(array.__proto__[50], "hello");

assertEq(50 in array, false);

array.__proto__.a = "world";

assertEq(array.__proto__.a, "world");

assertEq("a" in array, true);
// Returning {throw:} from onEnterFrame when resuming inside a try block in a
// generator causes control to jump to the finally block.

let g = newGlobal();
g.eval(`
    function* gen() {
        try {
            yield 0;
            return "fail";
        } finally {
            return "ok"; // preempts exception unwinding
        }
    }
`)

let dbg = new Debugger(g);
dbg.onEnterFrame = frame => {
    if (!("hits" in frame)) {
        frame.hits = 1;
    } else if (++frame.hits == 3) {
        // First hit is when calling gen();
        // second hit is resuming at the implicit initial yield;
        // third hit is resuming inside the try block.
        return {throw: "fit"};
    }
};

let it = g.gen();
let result = it.next();
assertEq(result.done, false);
assertEq(result.value, 0);
result = it.next();
assertEq(result.done, true);
assertEq(result.value, "ok");

vs

let g = newGlobal();

g.eval(`
    function* gen() {
        try {
            yield 0;
            return "fail";
        } finally {
            return "ok"; // preempts exception unwinding
        }
    }
`);

let dbg = new Debugger(g);

dbg.onEnterFrame = frame => {
    if (!"hits" in frame) {
        frame.hits = 1;
    } else if (++frame.hits == 3) {
        return {
            throw: "fit",
        };
    }

};

let it = g.gen();

let result = it.next();

assertEq(result.done, false);

assertEq(result.value, 0);

result = it.next();

assertEq(result.done, true);

assertEq(result.value, "ok");
gczeal(1);
var o0 = Function.prototype;
o1 = {};
var o4 = Error.prototype;
o5 = new Int32Array(100);
o6 = new Proxy({}, {})
o8 = new Proxy(function() { return {}; }, {
    get: function() { return 10; },
});
o9 = {};
var o10 = -500;
var o12 = new Int32Array(100);
function f0(o) {
}
function f1(o) {
}
function f3(o) {
    with(o) {}
    o[o5] = o5;
}
function f5(o) {
}for(var f2 in o9) {
    for(var i1=0; i1<83; i1++) {
        for(var i3=0; i3<98; i3++) {
            for(var x in f1) { f1[x]; };
        }
        Object.defineProperty(o0, 'constructor', {enumerable: true,unused: 1 });
        f1(f5);
        f4(f3);
        f3(o8);
        f2(o5);
        o9.toString(1, 2);
        f4.caller = o3;
        f2(o6);
        f0(f2);
        f1(f2);
        f0(f1);
        var key = Object.getOwnPropertyNames(o9)[2]; if(key) delete o9[key];
        var props = Object.getOwnPropertyNames(o5);
        if (props.length > 6) {
            var prop = props[6];
            o8[prop] = o5[prop];
        }
        f3(f1);
        f1(f5);
    }
    for(var o3 in f1) {
        f1(o3);
        f4(o3);
        o0 == f4;
        f1(f3);
        Object.freeze(o12);
        f0(o9);
        new f0(o1);
        o4 = o5.call(o4, o4, o4, o4, o4, o4);
        f2(o10);
        var prop = Object.getOwnPropertyNames(o0)[15];
        if (prop) { Object.defineProperty(o0, prop, {configurable: true,enumerable: true,get: function(){},set: function(){},unused: 1 }); }
        f3(f1);
        new f2(o0);
    }
    f5(o9);
    gc();
    f0(o2);
    f3(f4);
    new f4(o7);
    f1 = new o10(f1, f1, f1, f1);
    f5(o10);
    f5(o7);
    f0(o7);
    f1(o10);
    f3(o10);
    delete f0.constructor;
    f0(f3);
    f1 = wrap(f3);
    f4(f1);
    delete o1.prototype;
    f4(o5);
    f2(f2);
    o1 + '';
    f2(f2);
    f0(o12);
    f0(o12);
    f1(o3);
    o5[3] = 8.3;
    o10['__proto_' + '_'];
}
for(var o2 in f5) {
    for(var o10 in f3) {
        delete f2['__proto_' + '_'];
        o8 = f1.toString;
        f1(o1);
        f0(o9);
        f2(o12);
        var key = Object.getOwnPropertyNames(o3)[19]; if(key) o9 = o3[key];
        f1(o10);
        f4(f1);
        f1(o1);
        f1(o7);
        for(var x in o1) { o1[x]; };
        f0(o8);
        f4(o1);
        f0(o1);
        f0.p0 = o6;
        f3(o9);
        f5(o8);
        f2 >>> o7;
        if(o3 === o8) {}
        f5(o3);
    }
    o5[0] = f4;
    o0.caller = function() { };
    Object.freeze(f0);
    f4(o3);
    o7.p0 = o3;
    f1(f5);
    f4(o10);
    f2(o5);
    f2(o5);
    f0(o3);
    o8[o8] = o8;
    f0(o5);
    f1(o6);
    f2 = Object.create(o5);
    var key = Object.getOwnPropertyNames(o11)[23]; if(key) f2 = o11[key];
    f5(o9);
    o12 = o6.bind(o12, o12, o12);
    f5(f4);
    f1(o1);
    f0(o11);
    f1(o11);
    eval('f4');
    f4(o1);
    Object.isExtensible(o7);
}
(function() {
    f1(o12);
    f5 + '';
    if(o8 != o3) {}
})();
f1(o10);
f3(f0);
o4.toSource = function() { };
var _o = o1;
var prop = Object.getOwnPropertyNames(_o)[5];
if (prop) { _o[prop](o2, o2); }
f3(o0);
f1(f3);
Object.isExtensible(f1);

vs

gczeal(1);

var o0 = Function.prototype;

o1 = ({});

var o4 = Error.prototype;

o5 = new Int32Array(100);

o6 = new Proxy(({}), ({}));

o8 = new Proxy((function() {
    return {    };
}), ({
    get: (function() {
        return 10;
    }),
}));

o9 = ({});

var o10 = -500;

var o12 = new Int32Array(100);

function f0(o) { }

function f1(o) { }

function f3(o) {
    with (o) { 
        
    }
    o[o5] = o5;
}

function f5(o) { }

for (f2 in o9) {
    for (let i1 = 0;i1 < 83;i1++) {
        for (let i3 = 0;i3 < 98;i3++) {
            for (x in f1) {
                f1[x];
            }

            ;
        }

        Object.defineProperty(o0, 'constructor', {
            enumerable: true,
            unused: 1,
        });

        f1(f5);

        f4(f3);

        f3(o8);

        f2(o5);

        o9.toString(1, 2);

        f4.caller = o3;

        f2(o6);

        f0(f2);

        f1(f2);

        f0(f1);

        var key = Object.getOwnPropertyNames(o9)[2];

        if (key) delete o9[key];


        var props = Object.getOwnPropertyNames(o5);

        if (props.length > 6) {
            var prop = props[6];

            o8[prop] = o5[prop];
        }

        f3(f1);

        f1(f5);
    }

    for (o3 in f1) {
        f1(o3);

        f4(o3);

        o0 == f4;

        f1(f3);

        Object.freeze(o12);

        f0(o9);

        new f0(o1);

        o4 = o5.call(o4, o4, o4, o4, o4, o4);

        f2(o10);

        var prop = Object.getOwnPropertyNames(o0)[15];

        if (prop) {
            Object.defineProperty(o0, prop, {
                configurable: true,
                enumerable: true,
                get: function() { },
                set: function() { },
                unused: 1,
            });
        }

        f3(f1);

        new f2(o0);
    }

    f5(o9);

    gc();

    f0(o2);

    f3(f4);

    new f4(o7);

    f1 = new o10(f1, f1, f1, f1);

    f5(o10);

    f5(o7);

    f0(o7);

    f1(o10);

    f3(o10);

    delete f0.constructor;

    f0(f3);

    f1 = wrap(f3);

    f4(f1);

    delete o1.prototype;

    f4(o5);

    f2(f2);

    o1 + '';

    f2(f2);

    f0(o12);

    f0(o12);

    f1(o3);

    o5[3] = 8.3;

    o10['__proto_' + '_'];
}

for (o2 in f5) {
    for (o10 in f3) {
        delete f2['__proto_' + '_'];

        o8 = f1.toString;

        f1(o1);

        f0(o9);

        f2(o12);

        var key = Object.getOwnPropertyNames(o3)[19];

        if (key) o9 = o3[key];


        f1(o10);

        f4(f1);

        f1(o1);

        f1(o7);

        for (x in o1) {
            o1[x];
        }

        ;

        f0(o8);

        f4(o1);

        f0(o1);

        f0.p0 = o6;

        f3(o9);

        f5(o8);

        f2 >>> o7;

        if (o3 === o8) { 
            
        }

        f5(o3);
    }

    o5[0] = f4;

    o0.caller = function() { };

    Object.freeze(f0);

    f4(o3);

    o7.p0 = o3;

    f1(f5);

    f4(o10);

    f2(o5);

    f2(o5);

    f0(o3);

    o8[o8] = o8;

    f0(o5);

    f1(o6);

    f2 = Object.create(o5);

    var key = Object.getOwnPropertyNames(o11)[23];

    if (key) f2 = o11[key];


    f5(o9);

    o12 = o6.bind(o12, o12, o12);

    f5(f4);

    f1(o1);

    f0(o11);

    f1(o11);

    eval('f4');

    f4(o1);

    Object.isExtensible(o7);
}

(function() {
    f1(o12);
    f5 + '';
    if (o8 != o3) { 
        
    }
})();

f1(o10);

f3(f0);

o4.toSource = (function() { });

var _o = o1;

var prop = Object.getOwnPropertyNames(_o)[5];

if (prop) {
    _o[prop](o2, o2);
}

f3(o0);

f1(f3);

Object.isExtensible(f1);
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap reports a non-configurable property as
 * non-existent
 */
var target = {};
Object.defineProperty(target, 'foo', {
    configurable: false
});

var handler = { getOwnPropertyDescriptor: () => undefined };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    configurable: false,
}));

var handler = ({
    getOwnPropertyDescriptor: ()  => undefined,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
function a(stdlib) {
  "use asm";
  var imul = stdlib.Math.imul;
  function f() {
    return ((imul(-800, 0xf8ba1243)|0) % -1)|0;
  }
  return f;
}
var f = a(this);
assertEq(f(), 0);

vs

function a(stdlib) {
    "use asm";
    var imul = stdlib.Math.imul;
    function f() {
        return imul(-800, 0xf8ba1243) | 0 % -1 | 0;
    }
    return f;
}

var f = a(this);

assertEq(f(), 0);
var SECTION = "";
var VERSION = "";
function test() {}
function writeTestCaseResult( expect, actual, string ) {
  if (typeof document != "object" ||
!document.location.href.match(/jsreftest.html/)) {
  }
}
TIME_0000  = now = new Date;
TIME_NOW = now.valueOf();
function DaysInYear( y ) {
function MakeDate( day, time ) {

}
}
function TimeClip( t ) {
  if ( isNaN ) { Number.NaN; }
}
function runDSTOffsetCachingTestsFraction(part, parts) { print; };
test_times=( TIME_NOW, TIME_0000, ( SECTION, VERSION+".getUTCMinutes()", 
             TIME_NOW.test_times,VERSION.SECTION ) , TIME_0000, TIME_0000,
             0, 0 );
try { j = 0( SECTION, TimeClip(1.1), 0 ); } catch (e) {}

vs

var SECTION = "";

var VERSION = "";

function test() { }

function writeTestCaseResult(expect, actual, string) {
    if (typeof document != "object" || !document.location.href.match(/jsreftest.html/)) { 
        
    }
}

TIME_0000 = now = new Date();

TIME_NOW = now.valueOf();

function DaysInYear(y) {
    function MakeDate(day, time) { }
}

function TimeClip(t) {
    if (isNaN) {
        Number.NaN;
    }
}

function runDSTOffsetCachingTestsFraction(part, parts) {
    print;
}

;

test_times = TIME_NOW, TIME_0000, SECTION, VERSION + ".getUTCMinutes()", TIME_NOW.test_times, VERSION.SECTION, TIME_0000, TIME_0000, 0, 0;

try {
    j = 0(SECTION, TimeClip(1.1), 0);
} catch (e) { 
    
}
// Currently the Jit integration has a few issues, let's keep this test
// case deterministic.
//
//  - Baseline OSR increments the loop header twice.
//  - Ion is not updating any counter yet.
//
if (getJitCompilerOptions()["ion.warmup.trigger"] != 30)
  setJitCompilerOption("ion.warmup.trigger", 30);
if (getJitCompilerOptions()["baseline.warmup.trigger"] != 10)
  setJitCompilerOption("baseline.warmup.trigger", 10);

/*
 * These test cases are annotated with the output produced by LCOV [1].  Comment
 * starting with //<key> without any spaces are used as a reference for the code
 * coverage output.  Any "$" in these line comments are replaced by the current
 * line number, and any "%" are replaced with the current function name (defined
 * by the FN key).
 *
 * [1]  http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php
 */
function checkGetOffsetsCoverage(fun) {
  var keys = [ "TN", "SF", "FN", "FNDA", "FNF", "FNH", "BRDA", "BRF", "BRH", "DA", "LF", "LH" ];
  function startsWithKey(s) {
    for (k of keys) {
      if (s.startsWith(k))
        return true;
    }
    return false;
  };

  // Extract the body of the function, as the code to be executed.
  var source = fun.toSource();
  source = source.slice(source.indexOf('{') + 1, source.lastIndexOf('}'));

  // Extract comment starting with the previous keys, as a reference.
  var lcovRef = [];
  var currLine = 0;
  var currFun = [{name: "top-level", braces: 1}];
  for (var line of source.split('\n')) {
    currLine++;

    for (var comment of line.split("//").slice(1)) {
      if (!startsWithKey(comment))
        continue;
      comment = comment.trim();
      if (comment.startsWith("FN:"))
        currFun.push({ name: comment.split(',')[1], braces: 0 });
      var name = currFun[currFun.length - 1].name;
      if (!comment.startsWith("DA:"))
        continue;
      comment = {
        offset: null,
        lineNumber: currLine,
        columnNumber: null,
        count: comment.split(",")[1] | 0,
        script: (name == "top-level" ? undefined : name)
      };
      lcovRef.push(comment);
    }

    var deltaBraces = line.split('{').length - line.split('}').length;
    currFun[currFun.length - 1].braces += deltaBraces;
    if (currFun[currFun.length - 1].braces == 0)
      currFun.pop();
  }

  // Create a new global and instrument it with a debugger, to find all scripts,
  // created in the current global.
  var g = newGlobal();
  var dbg = Debugger(g);
  dbg.collectCoverageInfo = true;

  var topLevel = null;
  dbg.onNewScript = function (s) {
    topLevel = s;
    dbg.onNewScript = function () {};
  };

  // Evaluate the code, and collect the hit counts for each scripts / lines.
  g.eval(source);

  var coverageRes = [];
  function collectCoverage(s) {
    var res = s.getOffsetsCoverage();
    if (res == null)
      res = [{
        offset: null,
        lineNumber: null,
        columnNumber: null,
        script: s.displayName,
        count: 0
      }];
    else {
      res.map(function (e) {
        e.script = s.displayName;
        return e;
      });
    }
    coverageRes.push(res);
    s.getChildScripts().forEach(collectCoverage);
  };
  collectCoverage(topLevel);
  coverageRes = [].concat(...coverageRes);

  // Check that all the lines are present the result.
  function match(ref) {
    return function (entry) {
      return ref.lineNumber == entry.lineNumber && ref.script == entry.script;
    }
  }
  function ppObj(entry) {
    var str = "{";
    for (var k in entry) {
      if (entry[k] != null)
        str += " '" + k + "': " + entry[k] + ",";
    }
    str += "}";
    return str;
  }
  for (ref of lcovRef) {
    var res = coverageRes.find(match(ref));
    if (!res) {
      // getOffsetsCoverage returns null if we have no result for the
      // script. We added a fake entry with an undefined lineNumber, which is
      // used to match against the modified reference.
      var missRef = Object.create(ref);
      missRef.lineNumber = null;
      res = coverageRes.find(match(missRef));
    }

    if (!res || res.count != ref.count) {
      print("Cannot find `" + ppObj(ref) + "` in the following results:\n", coverageRes.map(ppObj).join("\n"));
      print("In the following source:\n", source);
      assertEq(true, false);
    }
  }
}

checkGetOffsetsCoverage(function () { //FN:$,top-level
  ",".split(','); //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  function f() {    //FN:$,f
    ",".split(','); //DA:$,0
  }
  ",".split(',');   //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  function f() {    //FN:$,f
    ",".split(','); //DA:$,1
  }
  f();              //DA:$,1
});

checkGetOffsetsCoverage(function () { ','.split(','); //FN:$,top-level //DA:$,1
});

checkGetOffsetsCoverage(function () { function f() { ','.split(','); } //FN:$,top-level //FN:$,f //DA:$,1
  f(); //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 3)      //DA:$,1
    l.push('');           //DA:$,0
  l.pop();                //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  if (l.length == 2)      //DA:$,1
    l.push('');           //DA:$,1
  l.pop();                //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  if (l.length == 3)      //DA:$,1
    l.push('');           //DA:$,0
  else
    l.pop();              //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  if (l.length == 2)      //DA:$,1
    l.push('');           //DA:$,1
  else
    l.pop();              //DA:$,0
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  if (l.length == 2)      //DA:$,1
    l.push('');           //DA:$,1
  else {
    if (l.length == 1)    //DA:$,0
      l.pop();            //DA:$,0
  }
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  function f(i) { //FN:$,f
    var x = 0;    //DA:$,2
    while (i--) { // Currently OSR wrongly count the loop header twice.
                  // So instead of DA:$,12 , we have DA:$,13 .
      x += i;     //DA:$,10
      x = x / 2;  //DA:$,10
    }
    return x;     //DA:$,2
  }

  f(5);           //DA:$,1
  f(5);           //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  try {                     //DA:$,1
    var l = ",".split(','); //DA:$,1
    if (l.length == 2) {    //DA:$,1
      l.push('');           //DA:$,1
      throw l;              //DA:$,1
    }
    l.pop();                //DA:$,0
  } catch (x) {             //DA:$,1
    x.pop();                //DA:$,1
  }
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(',');   //DA:$,1
  try {                     //DA:$,1
    try {                   //DA:$,1
      if (l.length == 2) {  //DA:$,1
        l.push('');         //DA:$,1
        throw l;            //DA:$,1
      }
      l.pop();              //DA:$,0
    } finally {             //DA:$,1
      l.pop();              //DA:$,1
    }
  } catch (x) {             //DA:$,1
  }
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  function f() {            //FN:$,f
    throw 1;                //DA:$,1
    f();                    //DA:$,0
  }
  var l = ",".split(',');   //DA:$,1
  try {                     //DA:$,1
    f();                    //DA:$,1
    f();                    //DA:$,0
  } catch (x) {             //DA:$,1
  }
});


// Test TableSwitch opcode
checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case 0:
      l.push('0');        //DA:$,0
      break;
    case 1:
      l.push('1');        //DA:$,0
      break;
    case 2:
      l.push('2');        //DA:$,1
      break;
    case 3:
      l.push('3');        //DA:$,0
      break;
  }
  l.pop();                //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case 5:
      l.push('5');        //DA:$,0
    case 4:
      l.push('4');        //DA:$,0
    case 3:
      l.push('3');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
  }
  l.pop();                //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case 2:
      l.push('2');        //DA:$,1
    case 5:
      l.push('5');        //DA:$,1
  }
  l.pop();                //DA:$,1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case 3:
      l.push('1');        //DA:$,0
    case 5:
      l.push('5');        //DA:$,0
  }
  l.pop();                //DA:$,1
});

// Unfortunately the differences between switch implementations leaks in the
// code coverage reports.
checkGetOffsetsCoverage(function () { //FN:$,top-level
  function f(a) {         //FN:$,f
    return a;             //DA:$,2
  }
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1
    case f(-42):          //DA:$,1
      l.push('1');        //DA:$,0
    case f(51):           //DA:$,1
      l.push('5');        //DA:$,0
  }
  l.pop();                //DA:$,1
});


checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,1 //BRDA:$,0,2,0 //BRDA:$,0,3,0
    case 0:
    case 1:
      l.push('0');        //DA:$,0
      l.push('1');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    case 2:
    case 3:
      l.push('2');        //DA:$,1
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
    default:
      l.push('1');        //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    default:
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,1 //BRDA:$,0,3,0 //BRDA:$,0,4,0
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    default:
      l.push('default');  //DA:$,0
    case 2:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:8
  //LH:5
  //BRF:5
  //BRH:1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ",".split(','); //DA:$,1
  switch (l.length) {     //DA:$,1 //BRDA:$,0,0,0 //BRDA:$,0,1,0 //BRDA:$,0,2,0 //BRDA:$,0,3,1
    case 0:
      l.push('0');        //DA:$,0
    case 1:
      l.push('1');        //DA:$,0
    default:
      l.push('2');        //DA:$,1
    case 3:
      l.push('3');        //DA:$,1
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:7
  //LH:5
  //BRF:4
  //BRH:1
});

checkGetOffsetsCoverage(function () { //FN:$,top-level //FNDA:1,%
  var l = ','.split(','); //DA:$,1
  if (l.length === 45) {  //DA:$,1 //BRDA:$,0,0,1 //BRDA:$,0,1,0
    switch (l[0]) {       //DA:$,0 //BRDA:$,1,0,- //BRDA:$,1,1,-
      case ',':
        l.push('0');      //DA:$,0
      default:
        l.push('1');      //DA:$,0
    }
  }
  l.pop();                //DA:$,1
  //FNF:1
  //FNH:1
  //LF:6
  //LH:3
  //BRF:4
  //BRH:1
});

// If you add a test case here, do the same in
// jit-test/tests/coverage/simple.js

vs

if (getJitCompilerOptions()["ion.warmup.trigger"] != 30) setJitCompilerOption("ion.warmup.trigger", 30);


if (getJitCompilerOptions()["baseline.warmup.trigger"] != 10) setJitCompilerOption("baseline.warmup.trigger", 10);


function checkGetOffsetsCoverage(fun) {
    var keys = ["TN", "SF", "FN", "FNDA", "FNF", "FNH", "BRDA", "BRF", "BRH", "DA", "LF", "LH",];
    function startsWithKey(s) {
        for (k of keys) {
            if (s.startsWith(k)) return true;

        }
        return false;
    }
    ;
    var source = fun.toSource();
    source = source.slice(source.indexOf('{') + 1, source.lastIndexOf('}'));
    var lcovRef = [];
    var currLine = 0;
    var currFun = [{
        name: "top-level",
        braces: 1,
    },];
    for (line of source.split('\n')) {
        currLine++;

        for (comment of line.split("//").slice(1)) {
            if (!startsWithKey(comment)) continue;


            comment = comment.trim();

            if (comment.startsWith("FN:")) currFun.push({
                name: comment.split(',')[1],
                braces: 0,
            });


            var name = currFun[currFun.length - 1].name;

            if (!comment.startsWith("DA:")) continue;


            comment = {
                offset: null,
                lineNumber: currLine,
                columnNumber: null,
                count: comment.split(",")[1] | 0,
                script: name == "top-level" ? undefined : name,
            };

            lcovRef.push(comment);
        }

        var deltaBraces = line.split('{').length - line.split('}').length;

        currFun[currFun.length - 1].braces += deltaBraces;

        if (currFun[currFun.length - 1].braces == 0) currFun.pop();

    }
    var g = newGlobal();
    var dbg = Debugger(g);
    dbg.collectCoverageInfo = true;
    var topLevel = null;
    dbg.onNewScript = function(s) {
        topLevel = s;
        dbg.onNewScript = function() { };
    };
    g.eval(source);
    var coverageRes = [];
    function collectCoverage(s) {
        var res = s.getOffsetsCoverage();
        if (res == null) res = [{
            offset: null,
            lineNumber: null,
            columnNumber: null,
            script: s.displayName,
            count: 0,
        },];
 else {
            res.map(function(e) {
                e.script = s.displayName;
                return e;
            });
        }
        coverageRes.push(res);
        s.getChildScripts().forEach(collectCoverage);
    }
    ;
    collectCoverage(topLevel);
    coverageRes = [].concat(...coverageRes);
    function match(ref) {
        return function(entry) {
            return ref.lineNumber == entry.lineNumber && ref.script == entry.script;
        };
    }
    function ppObj(entry) {
        var str = "{";
        for (k in entry) {
            if (entry[k] != null) str += " '" + k + "': " + entry[k] + ",";

        }
        str += "}";
        return str;
    }
    for (ref of lcovRef) {
        var res = coverageRes.find(match(ref));

        if (!res) {
            var missRef = Object.create(ref);

            missRef.lineNumber = null;

            res = coverageRes.find(match(missRef));
        }

        if (!res || res.count != ref.count) {
            print("Cannot find `" + ppObj(ref) + "` in the following results:\n", coverageRes.map(ppObj).join("\n"));

            print("In the following source:\n", source);

            assertEq(true, false);
        }
    }
}

checkGetOffsetsCoverage((function() {
    ",".split(',');
}));

checkGetOffsetsCoverage((function() {
    function f() {
        ",".split(',');
    }
    ",".split(',');
}));

checkGetOffsetsCoverage((function() {
    function f() {
        ",".split(',');
    }
    f();
}));

checkGetOffsetsCoverage((function() {
    ','.split(',');
}));

checkGetOffsetsCoverage((function() {
    function f() {
        ','.split(',');
    }
    f();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    if (l.length == 3) l.push('');

    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    if (l.length == 2) l.push('');

    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    if (l.length == 3) l.push('');
 else l.pop();

}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    if (l.length == 2) l.push('');
 else l.pop();

}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    if (l.length == 2) l.push('');
 else {
        if (l.length == 1) l.pop();

    }
}));

checkGetOffsetsCoverage((function() {
    function f(i) {
        var x = 0;
        while (i--) {
            x += i;

            x = x / 2;
        }
        return x;
    }
    f(5);
    f(5);
}));

checkGetOffsetsCoverage((function() {
    try {
        var l = ",".split(',');

        if (l.length == 2) {
            l.push('');

            throw l;
        }

        l.pop();
    } catch (x) {
        x.pop();
    }
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    try {
        try {
            if (l.length == 2) {
                l.push('');

                throw l;
            }

            l.pop();
        } finally {
            l.pop();
        }
    } catch (x) { 
        
    }
}));

checkGetOffsetsCoverage((function() {
    function f() {
        throw 1;
        f();
    }
    var l = ",".split(',');
    try {
        f();

        f();
    } catch (x) { 
        
    }
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        break;

        case 1:
            l.push('1');

        break;

        case 2:
            l.push('2');

        break;

        case 3:
            l.push('3');

        break;

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 5:
            l.push('5');

        case 4:
            l.push('4');

        case 3:
            l.push('3');

        case 2:
            l.push('2');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 2:
            l.push('2');

        case 5:
            l.push('5');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 3:
            l.push('1');

        case 5:
            l.push('5');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    function f(a) {
        return a;
    }
    var l = ",".split(',');
    switch (l.length) {
        case f(-42):
            l.push('1');

        case f(51):
            l.push('5');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
        case 1:
            l.push('0');

            l.push('1');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        case 2:
        case 3:
            l.push('2');

            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
        default:
            l.push('1');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        default:
        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        default:
            l.push('default');

        case 2:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ",".split(',');
    switch (l.length) {
        case 0:
            l.push('0');

        case 1:
            l.push('1');

        default:
            l.push('2');

        case 3:
            l.push('3');

    }
    l.pop();
}));

checkGetOffsetsCoverage((function() {
    var l = ','.split(',');
    if (l.length === 45) {
        switch (l[0]) {
            case ',':
                l.push('0');

            default:
                l.push('1');

        }
    }
    l.pop();
}));
// Accessing Debugger.Script's properties which triggers delazification can
// fail if the function for the script is optimized out.
// It shouldn't crash but just throw an error.

load(libdir + "asserts.js");

var g = newGlobal();
var dbg = new Debugger(g);
g.eval(`
function enclosing() {
    (function g1() {});
    (function* g2() {});
    (async function g3() {});
    (async function* g4() {});
    () => {};
    async () => {};
}
`);

for (const s of dbg.findScripts()) {
    if (!s.displayName) {
        continue;
    }

    try {
        s.lineCount;  // don't assert
    } catch (exc) {
        // If that didn't throw, it's fine. If it did, check the message.
        assertEq(exc.message, "function is optimized out");
    }
}

vs

load(libdir + "asserts.js");

var g = newGlobal();

var dbg = new Debugger(g);

g.eval(`
function enclosing() {
    (function g1() {});
    (function* g2() {});
    (async function g3() {});
    (async function* g4() {});
    () => {};
    async () => {};
}
`);

for (s of dbg.findScripts()) {
    if (!s.displayName) {
        continue;
    }

    try {
        s.lineCount;
    } catch (exc) {
        assertEq(exc.message, "function is optimized out");
    }
}
function f(x, y) {
    -(undefined ? 0 : 0);
    assertEq(y === y, true);
    return 0;
}
f(1, 2);
{
    f(3, 3.14);
    f(true, f(4, 5));

    function g() {}
}

vs

function f(x, y) {
    -undefined ? 0 : 0;
    assertEq(y === y, true);
    return 0;
}

f(1, 2);

{
    f(3, 3.14);

    f(true, f(4, 5));

    function g() { }
}
load(libdir + "asm.js");
load(libdir + "asserts.js");

var fatFunc = USE_ASM + '\n';
for (var i = 0; i < 100; i++)
    fatFunc += "function f" + i + "() { return ((f" + (i+1) + "()|0)+1)|0 }\n";
fatFunc += "function f100() { return 42 }\n";
fatFunc += "return f0";

for (let threshold of [0, 50, 100, 5000, -1]) {
    setJitCompilerOption("jump-threshold", threshold);

    assertEq(asmCompile(
        USE_ASM + `
            function h() { return ((g()|0)+2)|0 }
            function g() { return ((f()|0)+1)|0 }
            function f() { return 42 }
            return h
        `)()(), 45);

    enableGeckoProfiling();
    asmLink(asmCompile(USE_ASM + 'function f() {} function g() { f() } function h() { g() } return h'))();
    disableGeckoProfiling();

    assertEq(asmCompile(fatFunc)()(), 142);
}

vs

load(libdir + "asm.js");

load(libdir + "asserts.js");

var fatFunc = USE_ASM + '\n';

for (let i = 0;i < 100;i++) fatFunc += "function f" + i + "() { return ((f" + i + 1 + "()|0)+1)|0 }\n";

fatFunc += "function f100() { return 42 }\n";

fatFunc += "return f0";

for (threshold of [0, 50, 100, 5000, -1,]) {
    setJitCompilerOption("jump-threshold", threshold);

    assertEq(asmCompile(USE_ASM + `
            function h() { return ((g()|0)+2)|0 }
            function g() { return ((f()|0)+1)|0 }
            function f() { return 42 }
            return h
        `)()(), 45);

    enableGeckoProfiling();

    asmLink(asmCompile(USE_ASM + 'function f() {} function g() { f() } function h() { g() } return h'))();

    disableGeckoProfiling();

    assertEq(asmCompile(fatFunc)()(), 142);
}
// Setting a breakpoint in an eval script that is not on the stack. Bug 746973.
// We don't assert that the breakpoint actually hits because that depends on
// the eval cache, an implementation detail.

var g = newGlobal();
var dbg = Debugger(g);
g.eval("function f() { return eval('2+2'); }");
var s;
dbg.onNewScript = function (script) { s = script; };
g.f();
for (var offset of s.getLineOffsets(s.startLine))
    s.setBreakpoint(offset, {hit: function () {}});
assertEq(g.f(), 4);

vs

var g = newGlobal();

var dbg = Debugger(g);

g.eval("function f() { return eval('2+2'); }");

var s;

dbg.onNewScript = (function(script) {
    s = script;
});

g.f();

for (offset of s.getLineOffsets(s.startLine)) s.setBreakpoint(offset, {
    hit: function() { },
});

assertEq(g.f(), 4);
const mainGlobal = this;
const debuggerGlobal = newGlobal();

function Memory({global}) {
  this.dbg = new (debuggerGlobal.Debugger);
  this.gDO = this.dbg.addDebuggee(global);
}

Memory.prototype = {
  constructor: Memory,
  attach() { return Promise.resolve('fake attach result'); },
  detach() { return Promise.resolve('fake detach result'); },
  startRecordingAllocations() {
    this.dbg.memory.trackingAllocationSites = true;
    return Promise.resolve('fake startRecordingAllocations result');
  },
  stopRecordingAllocations() {
    this.dbg.memory.trackingAllocationSites = false;
    return Promise.resolve('fake stopRecordingAllocations result');
  },
  getAllocations() {
    return Promise.resolve({ allocations: this.dbg.memory.drainAllocationsLog() });
  }
};

function ok(cond, msg) {
  assertEq(!!cond, true, `ok(${uneval(cond)}, ${uneval(msg)})`);
}

const is = assertEq;

function startServerAndGetSelectedTabMemory() {
  let memory = new Memory({ global: mainGlobal });
  return Promise.resolve({ memory, client: 'fake client' });
}

function destroyServerAndFinish() {
  return Promise.resolve('fake destroyServerAndFinish result');
}

function* body() {
  let { memory, client } = yield startServerAndGetSelectedTabMemory();
  yield memory.attach();

  yield memory.startRecordingAllocations();
  ok(true, "Can start recording allocations");

  // Allocate some objects.

  let alloc1, alloc2, alloc3;

  /* eslint-disable max-nested-callbacks */
  (function outer() {
    (function middle() {
      (function inner() {
        alloc1 = {}; alloc1.line = Error().lineNumber;
        alloc2 = []; alloc2.line = Error().lineNumber;
        // eslint-disable-next-line new-parens
        alloc3 = new function () {}; alloc3.line = Error().lineNumber;
      }());
    }());
  }());
  /* eslint-enable max-nested-callbacks */

  let response = yield memory.getAllocations();

  yield memory.stopRecordingAllocations();
  ok(true, "Can stop recording allocations");

  // Filter out allocations by library and test code, and get only the
  // allocations that occurred in our test case above.

  function isTestAllocation(alloc) {
    let frame = alloc.frame;
    return frame
      && frame.functionDisplayName === "inner"
      && (frame.line === alloc1.line
          || frame.line === alloc2.line
          || frame.line === alloc3.line);
  }

  let testAllocations = response.allocations.filter(isTestAllocation);
  ok(testAllocations.length >= 3,
     "Should find our 3 test allocations (plus some allocations for the error "
     + "objects used to get line numbers)");

  // For each of the test case's allocations, ensure that the parent frame
  // indices are correct. Also test that we did get an allocation at each
  // line we expected (rather than a bunch on the first line and none on the
  // others, etc).

  let expectedLines = new Set([alloc1.line, alloc2.line, alloc3.line]);

  for (let alloc of testAllocations) {
    let innerFrame = alloc.frame;
    ok(innerFrame, "Should get the inner frame");
    is(innerFrame.functionDisplayName, "inner");
    expectedLines.delete(innerFrame.line);

    let middleFrame = innerFrame.parent;
    ok(middleFrame, "Should get the middle frame");
    is(middleFrame.functionDisplayName, "middle");

    let outerFrame = middleFrame.parent;
    ok(outerFrame, "Should get the outer frame");
    is(outerFrame.functionDisplayName, "outer");

    // Not going to test the rest of the frames because they are Task.jsm
    // and promise frames and it gets gross. Plus, I wouldn't want this test
    // to start failing if they changed their implementations in a way that
    // added or removed stack frames here.
  }

  is(expectedLines.size, 0,
     "Should have found all the expected lines");

  yield memory.detach();
  destroyServerAndFinish(client);
}

const generator = body();
loop(generator.next());

function loop({ value: promise, done }) {
  if (done)
    return;
  promise
    .catch(e => loop(generator.throw(e)))
    .then(v => { loop(generator.next(v)); })
    .catch(e => { print(`Error: ${e}\nstack:\n${e.stack}`); });
}

vs

const mainGlobal = this;

const debuggerGlobal = newGlobal();

function Memory({global,}) {
    this.dbg = new debuggerGlobal.Debugger();
    this.gDO = this.dbg.addDebuggee(global);
}

Memory.prototype = ({
    constructor: Memory,
    attach: (function() {
        return Promise.resolve('fake attach result');
    }),
    detach: (function() {
        return Promise.resolve('fake detach result');
    }),
    startRecordingAllocations: (function() {
        this.dbg.memory.trackingAllocationSites = true;
        return Promise.resolve('fake startRecordingAllocations result');
    }),
    stopRecordingAllocations: (function() {
        this.dbg.memory.trackingAllocationSites = false;
        return Promise.resolve('fake stopRecordingAllocations result');
    }),
    getAllocations: (function() {
        return Promise.resolve({
            allocations: this.dbg.memory.drainAllocationsLog(),
        });
    }),
});

function ok(cond, msg) {
    assertEq(!!cond, true, `ok(${uneval(cond)}, {uneval(msg)})`);
}

const is = assertEq;

function startServerAndGetSelectedTabMemory() {
    let memory = new Memory({
        global: mainGlobal,
    });
    return Promise.resolve({
        memory,
        client: 'fake client',
    });
}

function destroyServerAndFinish() {
    return Promise.resolve('fake destroyServerAndFinish result');
}

function *body() {
    let {memory, client,    } = yield startServerAndGetSelectedTabMemory();
    yield memory.attach();
    yield memory.startRecordingAllocations();
    ok(true, "Can start recording allocations");
    let alloc1, alloc2, alloc3;
    function outer() {
        function middle() {
            function inner() {
                alloc1 = {                };
                alloc1.line = Error().lineNumber;
                alloc2 = [];
                alloc2.line = Error().lineNumber;
                alloc3 = new function() { }();
                alloc3.line = Error().lineNumber;
            }();
        }();
    }();
    let response = yield memory.getAllocations();
    yield memory.stopRecordingAllocations();
    ok(true, "Can stop recording allocations");
    function isTestAllocation(alloc) {
        let frame = alloc.frame;
        return frame && frame.functionDisplayName === "inner" && frame.line === alloc1.line || frame.line === alloc2.line || frame.line === alloc3.line;
    }
    let testAllocations = response.allocations.filter(isTestAllocation);
    ok(testAllocations.length >= 3, "Should find our 3 test allocations (plus some allocations for the error " + "objects used to get line numbers)");
    let expectedLines = new Set([alloc1.line, alloc2.line, alloc3.line,]);
    for (alloc of testAllocations) {
        let innerFrame = alloc.frame;

        ok(innerFrame, "Should get the inner frame");

        is(innerFrame.functionDisplayName, "inner");

        expectedLines.delete(innerFrame.line);

        let middleFrame = innerFrame.parent;

        ok(middleFrame, "Should get the middle frame");

        is(middleFrame.functionDisplayName, "middle");

        let outerFrame = middleFrame.parent;

        ok(outerFrame, "Should get the outer frame");

        is(outerFrame.functionDisplayName, "outer");
    }
    is(expectedLines.size, 0, "Should have found all the expected lines");
    yield memory.detach();
    destroyServerAndFinish(client);
}

const generator = body();

loop(generator.next());

function loop({value: promise, done,}) {
    if (done) return;

    promise.catch(e => loop(generator.throw(e))).then(v => {
        loop(generator.next(v));
    }).catch(e => {
        print(`Error: ${e}\nstack:\n{e.stack}`);
    });
}
load(libdir + "asserts.js");
// Test ES6 Proxy trap compliance for Object.isExtensible() on exotic proxy
// objects.
var unsealed = {};
var sealed = Object.seal({});
var handler = {};

assertEq(Object.isExtensible(unsealed), true);
assertEq(Object.isExtensible(sealed), false);

var targetSealed = new Proxy(sealed, handler);
var targetUnsealed = new Proxy(unsealed, handler);

var handlerCalled = false;

function testExtensible(target, expectedResult, shouldIgnoreHandler = false)
{
    for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
        handlerCalled = false;
        if (typeof expectedResult === "boolean")
            assertEq(Object.isExtensible(p), expectedResult, "Must return the correct value.");
        else
            assertThrowsInstanceOf(() => Object.isExtensible(p), expectedResult);
        assertEq(handlerCalled, !shouldIgnoreHandler, "Must call handler appropriately");
    }
}

// without traps, forward to the target
// First, make sure we get the obvious answer on a non-exotic target.
testExtensible(sealed, false, /* shouldIgnoreHandler = */true);
testExtensible(unsealed, true, /* shouldIgnoreHandler = */true);

// Now, keep everyone honest. What if the target itself is a proxy?
// Note that we cheat a little. |handlerCalled| is true in a sense, just not
// for the toplevel handler.
// While we're here, test that the argument is passed correctly.
var targetsTarget = {};
function ensureCalled(target) { assertEq(target, targetsTarget); handlerCalled = true; return true; }
var proxyTarget = new Proxy(targetsTarget, { isExtensible : ensureCalled });
testExtensible(proxyTarget, true);

// What if the trap says it's necessarily sealed?
function fakeSealed() { handlerCalled = true; return false; }
handler.isExtensible = fakeSealed;
testExtensible(targetSealed, false);
testExtensible(targetUnsealed, TypeError);

// What if the trap says it's never sealed?
function fakeUnsealed() { handlerCalled = true; return true; }
handler.isExtensible = fakeUnsealed;
testExtensible(targetSealed, TypeError);
testExtensible(targetUnsealed, true);

// make sure we are able to prevent further extensions mid-flight and throw if the
// hook tries to lie.
function makeSealedTruth(target) { handlerCalled = true; Object.preventExtensions(target); return false; }
function makeSealedLie(target) { handlerCalled = true; Object.preventExtensions(target); return true; }
handler.isExtensible = makeSealedTruth;
testExtensible({}, false);
handler.isExtensible = makeSealedLie;
testExtensible({}, TypeError);

// What if the trap doesn't directly return a boolean?
function falseyNonBool() { handlerCalled = true; return undefined; }
handler.isExtensible = falseyNonBool;
testExtensible(sealed, false);
testExtensible(unsealed, TypeError);

function truthyNonBool() { handlerCalled = true; return {}; }
handler.isExtensible = truthyNonBool;
testExtensible(sealed, TypeError);
testExtensible(unsealed, true);

// What if the trap throws?
function ExtensibleError() { }
ExtensibleError.prototype = new Error();
ExtensibleError.prototype.constructor = ExtensibleError;
function throwFromTrap() { throw new ExtensibleError(); }
handler.isExtensible = throwFromTrap;

// exercise some other code paths and make sure that they invoke the trap and
// can handle the ensuing error.
for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) {
    assertThrowsInstanceOf(function () { Object.isExtensible(p); },
                           ExtensibleError, "Must throw if the trap does.");
    assertThrowsInstanceOf(function () { Object.isFrozen(p); },
                           ExtensibleError, "Must throw if the trap does.");
    assertThrowsInstanceOf(function () { Object.isSealed(p); },
                           ExtensibleError, "Must throw if the trap does.");
}

// What if the trap likes to re-ask old questions?
for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) {
    handler.isExtensible = (() => Object.isExtensible(p));
    assertThrowsInstanceOf(() => Object.isExtensible(p),
                           InternalError, "Should allow and detect infinite recurison.");
}

vs

load(libdir + "asserts.js");

var unsealed = ({});

var sealed = Object.seal(({}));

var handler = ({});

assertEq(Object.isExtensible(unsealed), true);

assertEq(Object.isExtensible(sealed), false);

var targetSealed = new Proxy(sealed, handler);

var targetUnsealed = new Proxy(unsealed, handler);

var handlerCalled = false;

function testExtensible(target, expectedResult, shouldIgnoreHandler = false) {
    for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
        handlerCalled = false;

        if (typeof expectedResult === "boolean") assertEq(Object.isExtensible(p), expectedResult, "Must return the correct value.");
 else assertThrowsInstanceOf(()  => Object.isExtensible(p), expectedResult);


        assertEq(handlerCalled, !shouldIgnoreHandler, "Must call handler appropriately");
    }
}

testExtensible(sealed, false, true);

testExtensible(unsealed, true, true);

var targetsTarget = ({});

function ensureCalled(target) {
    assertEq(target, targetsTarget);
    handlerCalled = true;
    return true;
}

var proxyTarget = new Proxy(targetsTarget, ({
    isExtensible: ensureCalled,
}));

testExtensible(proxyTarget, true);

function fakeSealed() {
    handlerCalled = true;
    return false;
}

handler.isExtensible = fakeSealed;

testExtensible(targetSealed, false);

testExtensible(targetUnsealed, TypeError);

function fakeUnsealed() {
    handlerCalled = true;
    return true;
}

handler.isExtensible = fakeUnsealed;

testExtensible(targetSealed, TypeError);

testExtensible(targetUnsealed, true);

function makeSealedTruth(target) {
    handlerCalled = true;
    Object.preventExtensions(target);
    return false;
}

function makeSealedLie(target) {
    handlerCalled = true;
    Object.preventExtensions(target);
    return true;
}

handler.isExtensible = makeSealedTruth;

testExtensible(({}), false);

handler.isExtensible = makeSealedLie;

testExtensible(({}), TypeError);

function falseyNonBool() {
    handlerCalled = true;
    return undefined;
}

handler.isExtensible = falseyNonBool;

testExtensible(sealed, false);

testExtensible(unsealed, TypeError);

function truthyNonBool() {
    handlerCalled = true;
    return {    };
}

handler.isExtensible = truthyNonBool;

testExtensible(sealed, TypeError);

testExtensible(unsealed, true);

function ExtensibleError() { }

ExtensibleError.prototype = new Error();

ExtensibleError.prototype.constructor = ExtensibleError;

function throwFromTrap() {
    throw new ExtensibleError();
}

handler.isExtensible = throwFromTrap;

for (p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy,]) {
    assertThrowsInstanceOf(function() {
        Object.isExtensible(p);
    }, ExtensibleError, "Must throw if the trap does.");

    assertThrowsInstanceOf(function() {
        Object.isFrozen(p);
    }, ExtensibleError, "Must throw if the trap does.");

    assertThrowsInstanceOf(function() {
        Object.isSealed(p);
    }, ExtensibleError, "Must throw if the trap does.");
}

for (p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy,]) {
    handler.isExtensible = ()  => Object.isExtensible(p);

    assertThrowsInstanceOf(()  => Object.isExtensible(p), InternalError, "Should allow and detect infinite recurison.");
}
// Test that the same saved stack is only ever allocated once.

const stacks = [];

for (let i = 0; i < 10; i++) {
  stacks.push(saveStack());
}

const s = stacks.pop();
for (let stack of stacks) {
  assertEq(s, stack);
}

vs

const stacks = [];

for (let i = 0;i < 10;i++) {
    stacks.push(saveStack());
}

const s = stacks.pop();

for (stack of stacks) {
    assertEq(s, stack);
}
// |jit-test| error: Error: can't start debugging: a debuggee script is on the stack

var g = newGlobal();
var dbg = Debugger(g);
function loop(i) {
  var n = 0;
  for (n = 0; n < i; n++)
    debugger;
}
g.eval(loop.toSource());

var countDown = 20;
dbg.onDebuggerStatement = function (f) {
  // Should throw an error.
  if (countDown > 0 && --countDown == 0) {
    dbg.collectCoverageInfo = !dbg.collectCoverageInfo;
  }
};

dbg.collectCoverageInfo = false;
g.eval("loop("+ (2 * countDown) +");");

vs

var g = newGlobal();

var dbg = Debugger(g);

function loop(i) {
    var n = 0;
    for (n = 0;n < i;n++) debugger;;
}

g.eval(loop.toSource());

var countDown = 20;

dbg.onDebuggerStatement = (function(f) {
    if (countDown > 0 && --countDown == 0) {
        dbg.collectCoverageInfo = !dbg.collectCoverageInfo;
    }
});

dbg.collectCoverageInfo = false;

g.eval("loop(" + 2 * countDown + ");");
/*
 * Call the trap with the handler as the this value, and the target as the first
 * argument
 */
var target = {};
var called;
var handler = {
    ownKeys: function (target1) {
        assertEq(this, handler);
        assertEq(target1, target);
        called = true;
        return [];
    }
};

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    called = false;
    Object.keys(new Proxy(target, handler));
    assertEq(called, true);
}

vs

var target = ({});

var called;

var handler = ({
    ownKeys: (function(target1) {
        assertEq(this, handler);
        assertEq(target1, target);
        called = true;
        return [];
    }),
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    called = false;

    Object.keys(new Proxy(target, handler));

    assertEq(called, true);
}
var emptyArray = [];
var denseArray = [1, 2, 3, 4];
var sparseArray = [1,,2,,3,,4];
var bigArray = new Array();
for (var i = 0; i < 128; i++) {
    bigArray.push(i);
}
var nonArray = {0:1, 1:2, 2:3, 3:4, length:2};
var indexedGetterArray = new Array();
Object.defineProperty(indexedGetterArray, '2', {get:function () { return 51; }});

var ARRAYS = [emptyArray, denseArray, sparseArray, bigArray, nonArray, indexedGetterArray];

var targetFun = function (a, b, c, d) {
    if (a === undefined)
        a = 0;
    if (b === undefined)
        b = 0;
    if (c === undefined)
        c = 0;
    if (d === undefined)
        d = 0;
    this.count += arguments.length + a + b + c + d;
}

var PERMUTATIONS = ARRAYS.length * ARRAYS.length;
function arrayPermutation(num) {
    var idx1 = num % ARRAYS.length;
    var idx2 = ((num / ARRAYS.length)|0) % ARRAYS.length;
    var resultArray = [];
    resultArray.push(ARRAYS[idx1]);
    resultArray.push(ARRAYS[idx2]);
    return resultArray;
}
var EXPECTED_RESULTS = {
    0:0, 1:280, 2:200, 3:2680, 4:100, 5:1080, 6:280, 7:560, 8:480, 9:2960,
    10:380, 11:1360, 12:200, 13:480, 14:400, 15:2880, 16:300, 17:1280, 18:2680,
    19:2960, 20:2880, 21:5360, 22:2780, 23:3760, 24:100, 25:380, 26:300, 27:2780,
    28:200, 29:1180, 30:1080, 31:1360, 32:1280, 33:3760, 34:1180, 35:2160
};

var callerNo = 0;
function generateCaller() {
    var fn;

    // Salt eval-string with callerNo to make sure eval caching doesn't take effect.
    var s = "function caller" + callerNo + "(fn, thisObj, arrays) {" +
            "  for (var i = 0; i < arrays.length; i++) {" +
            "    fn.apply(thisObj, arrays[i]);" +
            "  }" +
            "}" +
            "fn = caller" + callerNo + ";";
    eval(s);
    return fn;
};

function main() {
    for (var i = 0; i < PERMUTATIONS; i++) {
        var obj = {count:0};
        var arrs = arrayPermutation(i);
        var fn = generateCaller(arrs.length);
        // Loop 20 times so baseline compiler has chance to kick in and compile the scripts.
        for (var j = 0; j < 20; j++)
            fn(targetFun, obj, arrs);
        assertEq(obj.count, EXPECTED_RESULTS[i]);
    }
}

main();

vs

var emptyArray = [];

var denseArray = [1, 2, 3, 4,];

var sparseArray = [1,, 2,, 3,, 4,];

var bigArray = new Array();

for (let i = 0;i < 128;i++) {
    bigArray.push(i);
}

var nonArray = ({
    0: 1,
    1: 2,
    2: 3,
    3: 4,
    length: 2,
});

var indexedGetterArray = new Array();

Object.defineProperty(indexedGetterArray, '2', ({
    get: (function() {
        return 51;
    }),
}));

var ARRAYS = [emptyArray, denseArray, sparseArray, bigArray, nonArray, indexedGetterArray,];

var targetFun = (function(a, b, c, d) {
    if (a === undefined) a = 0;

    if (b === undefined) b = 0;

    if (c === undefined) c = 0;

    if (d === undefined) d = 0;

    this.count += arguments.length + a + b + c + d;
});

var PERMUTATIONS = ARRAYS.length * ARRAYS.length;

function arrayPermutation(num) {
    var idx1 = num % ARRAYS.length;
    var idx2 = num / ARRAYS.length | 0 % ARRAYS.length;
    var resultArray = [];
    resultArray.push(ARRAYS[idx1]);
    resultArray.push(ARRAYS[idx2]);
    return resultArray;
}

var EXPECTED_RESULTS = ({
    0: 0,
    1: 280,
    2: 200,
    3: 2680,
    4: 100,
    5: 1080,
    6: 280,
    7: 560,
    8: 480,
    9: 2960,
    10: 380,
    11: 1360,
    12: 200,
    13: 480,
    14: 400,
    15: 2880,
    16: 300,
    17: 1280,
    18: 2680,
    19: 2960,
    20: 2880,
    21: 5360,
    22: 2780,
    23: 3760,
    24: 100,
    25: 380,
    26: 300,
    27: 2780,
    28: 200,
    29: 1180,
    30: 1080,
    31: 1360,
    32: 1280,
    33: 3760,
    34: 1180,
    35: 2160,
});

var callerNo = 0;

function generateCaller() {
    var fn;
    var s = "function caller" + callerNo + "(fn, thisObj, arrays) {" + "  for (var i = 0; i < arrays.length; i++) {" + "    fn.apply(thisObj, arrays[i]);" + "  }" + "}" + "fn = caller" + callerNo + ";";
    eval(s);
    return fn;
}

;

function main() {
    for (let i = 0;i < PERMUTATIONS;i++) {
        var obj = {
            count: 0,
        };

        var arrs = arrayPermutation(i);

        var fn = generateCaller(arrs.length);

        for (let j = 0;j < 20;j++) fn(targetFun, obj, arrs);

        assertEq(obj.count, EXPECTED_RESULTS[i]);
    }
}

main();
// |jit-test| error:TypeError

// Binary: cache/js-dbg-32-7504904b5f8f-linux
// Flags: -j
//
Object.extend = function(destination, source) {
    for (var property in source)
    destination[property] = source[property]
}
Object.extend(Function.prototype, {
    curry: function() {
        var __method = this,
        args = $A(arguments)
        return function() {
            return __method(
            arguments)
        }
    },
    wrap: function(wrapper) {
        return function() { ([](
            $A(arguments)))
        }
    }
})
function $A(iterable) {
    var length = iterable.length
    while (length--);
}
var ga = {
    c: 3,
    d: 4
}
ga.
__defineGetter__("", /x/.test.wrap("").curry(true, ""))
for (var p in ga) {
    ga[p]
}

vs

Object.extend = (function(destination, source) {
    for (property in source) destination[property] = source[property];
});

Object.extend(Function.prototype, ({
    curry: (function() {
        var __method = this, args = $A(arguments);
        return function() {
            return __method(arguments);
        };
    }),
    wrap: (function(wrapper) {
        return function() {
            []($A(arguments));
        };
    }),
}));

function $A(iterable) {
    var length = iterable.length;
    while (length--) ;
}

var ga = ({
    c: 3,
    d: 4,
});

ga.__defineGetter__("", /x/.test.wrap("").curry(true, ""));

for (p in ga) {
    ga[p];
}
g = newGlobal();
g.parent = this;

function installHook() {
    let calledTimes = 0;
    function hook(frame) {
        calledTimes++;
        switch (calledTimes) {
          case 1:
            // Proxy get trap
            assertEq(frame.type, "call");
            assertEq(frame.script.displayName.includes("get"), true);
            break;
          case 2:
            // wrapper function. There is no entry for notRun
            assertEq(frame.type, "call");
            assertEq(frame.script.displayName.includes("wrapper"), true);
            break;
          case 3:
            assertEq(frame.type, "global");
            // Force the top-level to return cleanly, so that we can tell
            // assertion failures from the intended throwing.
            return { return: undefined };

          default:
            // that's the whole chain.
            assertEq(false, true);
        }
    }

    Debugger(parent).onExceptionUnwind = hook;
}


g.eval("(" + installHook + ")()");

var handler = {
    get(t, p) {
        throw new TypeError;
    }
};

function notRun() {}

function wrapper() {
    var f = new Proxy(notRun, handler);
    new f();
}
wrapper();

vs

g = newGlobal();

g.parent = this;

function installHook() {
    let calledTimes = 0;
    function hook(frame) {
        calledTimes++;
        switch (calledTimes) {
            case 1:
                assertEq(frame.type, "call");

                assertEq(frame.script.displayName.includes("get"), true);

            break;

            case 2:
                assertEq(frame.type, "call");

                assertEq(frame.script.displayName.includes("wrapper"), true);

            break;

            case 3:
                assertEq(frame.type, "global");

                return {
                    return: undefined,
                };

            default:
                assertEq(false, true);

        }
    }
    Debugger(parent).onExceptionUnwind = hook;
}

g.eval("(" + installHook + ")()");

var handler = ({
    get: (function(t, p) {
        throw new TypeError();
    }),
});

function notRun() { }

function wrapper() {
    var f = new Proxy(notRun, handler);
    new f();
}

wrapper();
load(libdir + "asserts.js");

// Throw a TypeError if the trap reports an extensible object as non-extensible

var handler = { preventExtensions: () => true };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.preventExtensions(p), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    preventExtensions: ()  => true,
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.preventExtensions(p), TypeError);
// Forward to the target if the trap is not defined
var proto = Object.create(null, {
    'foo': {
        configurable: true
    }
});
var target = Object.create(proto, {
    'bar': {
        configurable: true
    }
});

for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
    assertEq('foo' in p, true);
    assertEq('bar' in p, true);
    assertEq('baz' in p, false);
    assertEq(Symbol() in p, false);
}

vs

var proto = Object.create(null, ({
    'foo': ({
        configurable: true,
    }),
}));

var target = Object.create(proto, ({
    'bar': ({
        configurable: true,
    }),
}));

for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy,]) {
    assertEq('foo' in p, true);

    assertEq('bar' in p, true);

    assertEq('baz' in p, false);

    assertEq(Symbol() in p, false);
}
// Binary: cache/js-dbg-32-96746395df4f-linux
// Flags: -j
//
var fs = { x: /a/, y: /a/, z: /a/ };
for (var p in fs) { this[fs[p]] = null; }

vs

var fs = ({
    x: /a/,
    y: /a/,
    z: /a/,
});

for (p in fs) {
    this[fs[p]] = null;
}
// |jit-test| error: Assertion failed: bad label: 2
try {
    this['Module'] = Module;
} catch (e) {
    this['Module'] = Module = {};
}
var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
var ENVIRONMENT_IS_WEB = typeof window === 'object';
var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
if (ENVIRONMENT_IS_SHELL) {
    Module['print'] = print;
    Module['arguments'] = [];
}
var Runtime = {
    alignMemory: function alignMemory(size, quantum) {},
}
    function SAFE_HEAP_CLEAR(dest) {
    }
    function SAFE_HEAP_STORE(dest, value, type, ignore) {
        setValue(dest, value, type, 1);
    }
    function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) {
	try { } catch(e) {};
        var ret = getValue(dest, type, 1);
        return ret;
    };
    function SAFE_HEAP_LOAD1(dest, type) {
	return getValue(dest, type, 1);
    };
function abort(text) {
    Module.print(text + ':\n' + (new Error).stack);
    throw "Assertion: " + text;
}
function assert(condition, text) {
    if (!condition) {
        abort('Assertion failed: ' + text);
    }
}
function setValue(ptr, value, type, noSafe) {
    if (type.charAt(type.length - 1) === '*') type = 'i32'; // pointers are 32-bit
    if (noSafe) {
        switch (type) {
            case 'i32':
                HEAP32[((ptr) >> 2)] = value;
        }
    }
}
function getValue(ptr, type, noSafe) {
    if (type.charAt(type.length - 1) === '*') type = 'i32'; // pointers are 32-bit
    if (noSafe) {
        switch (type) {
            case 'i32':
                return HEAP32[((ptr) >> 2)];
        }
    }
}
var ALLOC_STATIC = 2; // Cannot be freed
function allocate(slab, types, allocator, ptr) {}
var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 16777216;
var buffer = new ArrayBuffer(TOTAL_MEMORY);
HEAP32 = new Int32Array(buffer);
STACK_ROOT = STACKTOP = Runtime.alignMemory(1);
function intArrayFromString(stringy, dontAddNull, length /* optional */ ) {}
function __ZN11btRigidBody14getMotionStateEv($this_0_20_val) {
}
function __ZN16btCollisionWorld23getCollisionObjectArrayEv($this) {}
function __ZN20btAlignedObjectArrayIP17btCollisionObjectEixEi($this_0_3_val, $n) {}
function _main($argc, $argv) {
    label = 2;
    while (1) switch (label) {
        case 2:
            var $31 = __Znwj(268);
            var $32 = $31;
            var $67 = __ZN17btCollisionObjectnwEj();
            var $68 = $67;
            __ZN23btDiscreteDynamicsWorld12addRigidBodyEP11btRigidBody($32, $68);
            var $99 = $31;
            var $104 = __ZN23btDiscreteDynamicsWorld14stepSimulationEfif($32, .01666666753590107, 10, .01666666753590107);
            var $106 = __ZNK16btCollisionWorld22getNumCollisionObjectsEv($99);
            var $108 = __ZN16btCollisionWorld23getCollisionObjectArrayEv($99);
            var $_idx6 = $108 + 12 | 0;
            var $j_049_in = $106;
            var $j_049 = $j_049_in - 1 | 0;
            var $_idx6_val = SAFE_HEAP_LOAD($_idx6, "%class.btCollisionObject**", 0, 0);
            var $109 = __ZN20btAlignedObjectArrayIP17btCollisionObjectEixEi($_idx6_val, $j_049);
            var $110 = SAFE_HEAP_LOAD($109, "%class.btCollisionObject*", 0, 0);
            var $111 = __ZN11btRigidBody6upcastEP17btCollisionObject($110);
            var $_idx9 = $111 + 472 | 0;
            var $_idx9_val = SAFE_HEAP_LOAD($_idx9, "%class.btMotionState*", 0, 0);
            var $114 = __ZN11btRigidBody14getMotionStateEv($_idx9_val);
            var $138 = $i_057 + 1 | 0;
            var $139 = ($138 | 0) < 135;
            if ($139) {
                var $i_057 = $138;
                break;
            }
            assert(0, "bad label: " + label);
    }
}
Module["_main"] = _main;
function __ZN17btCollisionObjectnwEj() {
    return __Z22btAlignedAllocInternalji(608);
}
function __ZNK16btCollisionWorld22getNumCollisionObjectsEv($this) {}
function __ZN11btRigidBody6upcastEP17btCollisionObject($colObj) {
    label = 2;
    while (1) switch (label) {
        case 2:
            var $_0;
            return $_0;
    }
}
function __ZNK9btVector33dotERKS_($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val, $v_0_0_0_val, $v_0_0_1_val, $v_0_0_2_val) {
}
function __ZN20btAlignedObjectArrayIP11btRigidBodyEixEi($this_0_3_val, $n) {}
function __ZNK17btCollisionObject14getHitFractionEv($this_0_21_val) {}
function __ZN17btCollisionObject30getInterpolationWorldTransformEv($this) {}
function __ZNK17btCollisionObject30getInterpolationLinearVelocityEv($this) {}
function __ZNK17btCollisionObject31getInterpolationAngularVelocityEv($this) {}
function __ZN23btDiscreteDynamicsWorld28synchronizeSingleMotionStateEP11btRigidBody($this, $body) {
    assertEq($body, 16);
    var __stackBase__ = STACKTOP;
    while (1) switch (label) {
        case 2:
            var $interpolatedTransform = __stackBase__;
            var $4 = $body | 0;
            var $7 = __ZN17btCollisionObject30getInterpolationWorldTransformEv($4);
            var $8 = __ZNK17btCollisionObject30getInterpolationLinearVelocityEv($4);
            var $9 = __ZNK17btCollisionObject31getInterpolationAngularVelocityEv($4);
            var $10 = $this + 236 | 0;
            var $11 = SAFE_HEAP_LOAD($10, "float", 0, 0);
            var $_idx2 = $body + 240 | 0;
            var $_idx2_val = SAFE_HEAP_LOAD($_idx2, "float", 0, 0);
            var $12 = __ZNK17btCollisionObject14getHitFractionEv($_idx2_val);
            var $13 = $11 * $12;
            var $_idx3 = $8 | 0;
            var $_idx3_val = SAFE_HEAP_LOAD($_idx3, "float", 0, 0);
            var $_idx4 = $8 + 4 | 0;
            var $_idx4_val = SAFE_HEAP_LOAD($_idx4, "float", 0, 0);
            var $_idx5 = $8 + 8 | 0;
            var $_idx5_val = SAFE_HEAP_LOAD($_idx5, "float", 0, 0);
            __ZN15btTransformUtil18integrateTransformERK11btTransformRK9btVector3S5_fRS0_($7, $_idx3_val, $_idx4_val, $_idx5_val, $9, $13, $interpolatedTransform);
            return;
    }
}
function __ZN15btTransformUtil18integrateTransformERK11btTransformRK9btVector3S5_fRS0_($curTrans, $linvel_0_0_0_val, $linvel_0_0_1_val, $linvel_0_0_2_val, $angvel, $timeStep, $predictedTransform) {
    var __stackBase__ = STACKTOP;
    STACKTOP = STACKTOP + 132 | 0;
    while (1) {
	switch (label) {
        case 2:
            var $axis = __stackBase__ + 32;
            var $3 = __stackBase__ + 48;
            var $angvel_idx10 = $angvel | 0;
            var $angvel_idx10_val = SAFE_HEAP_LOAD($angvel_idx10, "float", 0, 0);
	    var $angvel_idx11 = $angvel + 4 | 0;
            var $angvel_idx11_val = SAFE_HEAP_LOAD($angvel_idx11, "float", 0, 0);
            var $angvel_idx12 = $angvel + 8 | 0;
            var $angvel_idx12_val = SAFE_HEAP_LOAD($angvel_idx12, "float", 0, 0);
            var $7 = __ZNK9btVector36lengthEv($angvel_idx10_val, $angvel_idx11_val, $angvel_idx12_val);
            var $8 = $7 * $timeStep;
            if ($8 > .7853981852531433) {} else {
                var $fAngle_0 = $7;
                label = 5;
            }
	    break;
        case 5:
            var $22 = $axis;
            var $23 = $3;
            SAFE_HEAP_STORE($22 + 12, SAFE_HEAP_LOAD1($23 + 12, "i32"), "i32", 0);
	    assertEq(SAFE_HEAP_LOAD1(0, "%class.btRigidBody*"), 16);
            label = 7;
            break;
        case 6:
            SAFE_HEAP_STORE($29 + 12, SAFE_HEAP_LOAD1($30 + 12, "i32"), "i32", 0);
        case 7:
            for (var i = __stackBase__; i < STACKTOP; i++) SAFE_HEAP_CLEAR(i);
            return;
	}
    }
}
function __ZN23btDiscreteDynamicsWorld12addRigidBodyEP11btRigidBody($this, $body) {
    SAFE_HEAP_STORE(STACKTOP, $body, "%class.btRigidBody*", 0);
    assertEq(SAFE_HEAP_LOAD(0, "%class.btRigidBody*", 0, 0), 16);
}
function __ZN23btDiscreteDynamicsWorld23synchronizeMotionStatesEv($this) {
    var $20 = SAFE_HEAP_LOAD(0, "%class.btRigidBody*", 0, 0);
    assertEq($20, 16);
    __ZN23btDiscreteDynamicsWorld28synchronizeSingleMotionStateEP11btRigidBody($this, $20);
}
function __ZN23btDiscreteDynamicsWorld14stepSimulationEfif($this, $timeStep, $maxSubSteps, $fixedTimeStep) {
    label = 2;
    while (1) switch (label) {
        case 2:
            var $numSimulationSubSteps_0;
            __ZN23btDiscreteDynamicsWorld23synchronizeMotionStatesEv($this);
            return $numSimulationSubSteps_0;
    }
}
function __ZNK9btVector37length2Ev($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val) {
    return __ZNK9btVector33dotERKS_($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val, $this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val);
}
function __Z6btSqrtf($y) {
    return Math.sqrt($y);
}
function __ZNK9btVector36lengthEv($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val) {
    return __Z6btSqrtf(__ZNK9btVector37length2Ev($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val));
}
function __ZL21btAlignedAllocDefaultji($size, $alignment) {
    while (1) switch (label) {
        case 2:
            var $1 = $size + 4 | 0;
            var $2 = $alignment - 1 | 0;
            var $3 = $1 + $2 | 0;
            var $4 = __ZL14btAllocDefaultj($3);
            var $7 = $4 + 4 | 0;
            var $8 = $7;
            var $9 = $alignment - $8 | 0;
            var $10 = $9 & $2;
            var $_sum = $10 + 4 | 0;
            var $11 = $4 + $_sum | 0;
            var $ret_0 = $11;
            return $ret_0;
    }
}
function __ZL14btAllocDefaultj($size) {
    return _malloc($size);
}
function __Z22btAlignedAllocInternalji($size) {
    return __ZL21btAlignedAllocDefaultji($size, 16);
}
function _malloc($bytes) {
    while (1) switch (label) {
        case 2:
            var $189 = SAFE_HEAP_LOAD(5244020, "%struct.malloc_chunk*", 0, 0);
            var $198 = $189 + 8 | 0;
            var $199 = $198;
            var $mem_0 = $199;
            return $mem_0;
    }
}
function __Znwj($size) {
    while (1) switch (label) {
        case 2:
            var $1 = ($size | 0) == 0;
            var $_size = $1 ? 1 : $size;
            var $3 = _malloc($_size);
            return $3;
    }
}
Module.callMain = function callMain(args) {
    var argc = args.length + 1;
    var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_STATIC)];
    return Module['_main'](argc, argv, 0);
}
function run(args) {
    args = args || Module['arguments'];
    function doRun() {
        if (Module['_main']) {
            ret = Module.callMain(args);
        }
    }
    if (Module['setStatus']) {} else {
        return doRun();
    }
}
run();

vs

try {
    this['Module'] = Module;
} catch (e) {
    this['Module'] = Module = ({    });
}

var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';

var ENVIRONMENT_IS_WEB = typeof window === 'object';

var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';

var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;

if (ENVIRONMENT_IS_SHELL) {
    Module['print'] = print;

    Module['arguments'] = [];
}

var Runtime = ({
    alignMemory: (function alignMemory(size, quantum) { }),
});

function SAFE_HEAP_CLEAR(dest) { }

function SAFE_HEAP_STORE(dest, value, type, ignore) {
    setValue(dest, value, type, 1);
}

function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) {
    try { 
        
    } catch (e) { 
        
    }
    ;
    var ret = getValue(dest, type, 1);
    return ret;
}

;

function SAFE_HEAP_LOAD1(dest, type) {
    return getValue(dest, type, 1);
}

;

function abort(text) {
    Module.print(text + ':\n' + new Error().stack);
    throw "Assertion: " + text;
}

function assert(condition, text) {
    if (!condition) {
        abort('Assertion failed: ' + text);
    }
}

function setValue(ptr, value, type, noSafe) {
    if (type.charAt(type.length - 1) === '*') type = 'i32';

    if (noSafe) {
        switch (type) {
            case 'i32':
                HEAP32[ptr >> 2] = value;

        }
    }
}

function getValue(ptr, type, noSafe) {
    if (type.charAt(type.length - 1) === '*') type = 'i32';

    if (noSafe) {
        switch (type) {
            case 'i32':
                return HEAP32[ptr >> 2];

        }
    }
}

var ALLOC_STATIC = 2;

function allocate(slab, types, allocator, ptr) { }

var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 16777216;

var buffer = new ArrayBuffer(TOTAL_MEMORY);

HEAP32 = new Int32Array(buffer);

STACK_ROOT = STACKTOP = Runtime.alignMemory(1);

function intArrayFromString(stringy, dontAddNull, length) { }

function __ZN11btRigidBody14getMotionStateEv($this_0_20_val) { }

function __ZN16btCollisionWorld23getCollisionObjectArrayEv($this) { }

function __ZN20btAlignedObjectArrayIP17btCollisionObjectEixEi($this_0_3_val, $n) { }

function _main($argc, $argv) {
    label = 2;
    while (1) switch (label) {
        case 2:
            var $31 = __Znwj(268);

            var $32 = $31;

            var $67 = __ZN17btCollisionObjectnwEj();

            var $68 = $67;

            __ZN23btDiscreteDynamicsWorld12addRigidBodyEP11btRigidBody($32, $68);

            var $99 = $31;

            var $104 = __ZN23btDiscreteDynamicsWorld14stepSimulationEfif($32, .01666666753590107, 10, .01666666753590107);

            var $106 = __ZNK16btCollisionWorld22getNumCollisionObjectsEv($99);

            var $108 = __ZN16btCollisionWorld23getCollisionObjectArrayEv($99);

            var $_idx6 = $108 + 12 | 0;

            var $j_049_in = $106;

            var $j_049 = $j_049_in - 1 | 0;

            var $_idx6_val = SAFE_HEAP_LOAD($_idx6, "%class.btCollisionObject**", 0, 0);

            var $109 = __ZN20btAlignedObjectArrayIP17btCollisionObjectEixEi($_idx6_val, $j_049);

            var $110 = SAFE_HEAP_LOAD($109, "%class.btCollisionObject*", 0, 0);

            var $111 = __ZN11btRigidBody6upcastEP17btCollisionObject($110);

            var $_idx9 = $111 + 472 | 0;

            var $_idx9_val = SAFE_HEAP_LOAD($_idx9, "%class.btMotionState*", 0, 0);

            var $114 = __ZN11btRigidBody14getMotionStateEv($_idx9_val);

            var $138 = $i_057 + 1 | 0;

            var $139 = $138 | 0 < 135;

            if ($139) {
                var $i_057 = $138;

                break;
            }

            assert(0, "bad label: " + label);

    }
}

Module["_main"] = _main;

function __ZN17btCollisionObjectnwEj() {
    return __Z22btAlignedAllocInternalji(608);
}

function __ZNK16btCollisionWorld22getNumCollisionObjectsEv($this) { }

function __ZN11btRigidBody6upcastEP17btCollisionObject($colObj) {
    label = 2;
    while (1) switch (label) {
        case 2:
            var $_0;

            return $_0;

    }
}

function __ZNK9btVector33dotERKS_($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val, $v_0_0_0_val, $v_0_0_1_val, $v_0_0_2_val) { }

function __ZN20btAlignedObjectArrayIP11btRigidBodyEixEi($this_0_3_val, $n) { }

function __ZNK17btCollisionObject14getHitFractionEv($this_0_21_val) { }

function __ZN17btCollisionObject30getInterpolationWorldTransformEv($this) { }

function __ZNK17btCollisionObject30getInterpolationLinearVelocityEv($this) { }

function __ZNK17btCollisionObject31getInterpolationAngularVelocityEv($this) { }

function __ZN23btDiscreteDynamicsWorld28synchronizeSingleMotionStateEP11btRigidBody($this, $body) {
    assertEq($body, 16);
    var __stackBase__ = STACKTOP;
    while (1) switch (label) {
        case 2:
            var $interpolatedTransform = __stackBase__;

            var $4 = $body | 0;

            var $7 = __ZN17btCollisionObject30getInterpolationWorldTransformEv($4);

            var $8 = __ZNK17btCollisionObject30getInterpolationLinearVelocityEv($4);

            var $9 = __ZNK17btCollisionObject31getInterpolationAngularVelocityEv($4);

            var $10 = $this + 236 | 0;

            var $11 = SAFE_HEAP_LOAD($10, "float", 0, 0);

            var $_idx2 = $body + 240 | 0;

            var $_idx2_val = SAFE_HEAP_LOAD($_idx2, "float", 0, 0);

            var $12 = __ZNK17btCollisionObject14getHitFractionEv($_idx2_val);

            var $13 = $11 * $12;

            var $_idx3 = $8 | 0;

            var $_idx3_val = SAFE_HEAP_LOAD($_idx3, "float", 0, 0);

            var $_idx4 = $8 + 4 | 0;

            var $_idx4_val = SAFE_HEAP_LOAD($_idx4, "float", 0, 0);

            var $_idx5 = $8 + 8 | 0;

            var $_idx5_val = SAFE_HEAP_LOAD($_idx5, "float", 0, 0);

            __ZN15btTransformUtil18integrateTransformERK11btTransformRK9btVector3S5_fRS0_($7, $_idx3_val, $_idx4_val, $_idx5_val, $9, $13, $interpolatedTransform);

            return;

    }
}

function __ZN15btTransformUtil18integrateTransformERK11btTransformRK9btVector3S5_fRS0_($curTrans, $linvel_0_0_0_val, $linvel_0_0_1_val, $linvel_0_0_2_val, $angvel, $timeStep, $predictedTransform) {
    var __stackBase__ = STACKTOP;
    STACKTOP = STACKTOP + 132 | 0;
    while (1) {
        switch (label) {
            case 2:
                var $axis = __stackBase__ + 32;

                var $3 = __stackBase__ + 48;

                var $angvel_idx10 = $angvel | 0;

                var $angvel_idx10_val = SAFE_HEAP_LOAD($angvel_idx10, "float", 0, 0);

                var $angvel_idx11 = $angvel + 4 | 0;

                var $angvel_idx11_val = SAFE_HEAP_LOAD($angvel_idx11, "float", 0, 0);

                var $angvel_idx12 = $angvel + 8 | 0;

                var $angvel_idx12_val = SAFE_HEAP_LOAD($angvel_idx12, "float", 0, 0);

                var $7 = __ZNK9btVector36lengthEv($angvel_idx10_val, $angvel_idx11_val, $angvel_idx12_val);

                var $8 = $7 * $timeStep;

                if ($8 > .7853981852531433) { 
                    
                } else {
                    var $fAngle_0 = $7;

                    label = 5;
                }

            break;

            case 5:
                var $22 = $axis;

                var $23 = $3;

                SAFE_HEAP_STORE($22 + 12, SAFE_HEAP_LOAD1($23 + 12, "i32"), "i32", 0);

                assertEq(SAFE_HEAP_LOAD1(0, "%class.btRigidBody*"), 16);

                label = 7;

            break;

            case 6:
                SAFE_HEAP_STORE($29 + 12, SAFE_HEAP_LOAD1($30 + 12, "i32"), "i32", 0);

            case 7:
                for (let i = __stackBase__;i < STACKTOP;i++) SAFE_HEAP_CLEAR(i);

                return;

        }
    }
}

function __ZN23btDiscreteDynamicsWorld12addRigidBodyEP11btRigidBody($this, $body) {
    SAFE_HEAP_STORE(STACKTOP, $body, "%class.btRigidBody*", 0);
    assertEq(SAFE_HEAP_LOAD(0, "%class.btRigidBody*", 0, 0), 16);
}

function __ZN23btDiscreteDynamicsWorld23synchronizeMotionStatesEv($this) {
    var $20 = SAFE_HEAP_LOAD(0, "%class.btRigidBody*", 0, 0);
    assertEq($20, 16);
    __ZN23btDiscreteDynamicsWorld28synchronizeSingleMotionStateEP11btRigidBody($this, $20);
}

function __ZN23btDiscreteDynamicsWorld14stepSimulationEfif($this, $timeStep, $maxSubSteps, $fixedTimeStep) {
    label = 2;
    while (1) switch (label) {
        case 2:
            var $numSimulationSubSteps_0;

            __ZN23btDiscreteDynamicsWorld23synchronizeMotionStatesEv($this);

            return $numSimulationSubSteps_0;

    }
}

function __ZNK9btVector37length2Ev($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val) {
    return __ZNK9btVector33dotERKS_($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val, $this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val);
}

function __Z6btSqrtf($y) {
    return Math.sqrt($y);
}

function __ZNK9btVector36lengthEv($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val) {
    return __Z6btSqrtf(__ZNK9btVector37length2Ev($this_0_0_0_val, $this_0_0_1_val, $this_0_0_2_val));
}

function __ZL21btAlignedAllocDefaultji($size, $alignment) {
    while (1) switch (label) {
        case 2:
            var $1 = $size + 4 | 0;

            var $2 = $alignment - 1 | 0;

            var $3 = $1 + $2 | 0;

            var $4 = __ZL14btAllocDefaultj($3);

            var $7 = $4 + 4 | 0;

            var $8 = $7;

            var $9 = $alignment - $8 | 0;

            var $10 = $9 & $2;

            var $_sum = $10 + 4 | 0;

            var $11 = $4 + $_sum | 0;

            var $ret_0 = $11;

            return $ret_0;

    }
}

function __ZL14btAllocDefaultj($size) {
    return _malloc($size);
}

function __Z22btAlignedAllocInternalji($size) {
    return __ZL21btAlignedAllocDefaultji($size, 16);
}

function _malloc($bytes) {
    while (1) switch (label) {
        case 2:
            var $189 = SAFE_HEAP_LOAD(5244020, "%struct.malloc_chunk*", 0, 0);

            var $198 = $189 + 8 | 0;

            var $199 = $198;

            var $mem_0 = $199;

            return $mem_0;

    }
}

function __Znwj($size) {
    while (1) switch (label) {
        case 2:
            var $1 = $size | 0 == 0;

            var $_size = $1 ? 1 : $size;

            var $3 = _malloc($_size);

            return $3;

    }
}

Module.callMain = (function callMain(args) {
    var argc = args.length + 1;
    var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_STATIC),];
    return Module['_main'](argc, argv, 0);
});

function run(args) {
    args = args || Module['arguments'];
    function doRun() {
        if (Module['_main']) {
            ret = Module.callMain(args);
        }
    }
    if (Module['setStatus']) { 
        
    } else {
        return doRun();
    }
}

run();
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap skips an existing own enumerable property on a
 * non-extensible object
 */
var target = {};
Object.defineProperty(target, 'foo', {
    enumerable: true,
    configurable: true
});
Object.preventExtensions(target);

var handler = { ownKeys: () => [] };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.keys(p), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    enumerable: true,
    configurable: true,
}));

Object.preventExtensions(target);

var handler = ({
    ownKeys: ()  => [],
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.keys(p), TypeError);
// Test that SavedFrame instances are frozen and can't be messed with.

// Strict mode so that mutating frozen objects doesn't silently fail.
"use strict";

const s = saveStack();

load(libdir + 'asserts.js');

assertThrowsInstanceOf(() => s.source = "fake.url",
                       TypeError);

assertThrowsInstanceOf(() => {
  Object.defineProperty(s.__proto__, "line", {
    get: () => 0
  })
}, TypeError);

vs

'use strict';

const s = saveStack();

load(libdir + 'asserts.js');

assertThrowsInstanceOf(()  => s.source = "fake.url", TypeError);

assertThrowsInstanceOf(()  => {
    Object.defineProperty(s.__proto__, "line", {
        get: ()  => 0,
    });
}, TypeError);
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

setJitCompilerOption("ion.warmup.trigger", 30);

var Vec3u16Type = TypedObject.uint16.array(3);
var PairVec3u16Type = new TypedObject.StructType({fst: Vec3u16Type,
                                                  snd: Vec3u16Type});

function foo_u16() {
  for (var i = 0; i < 5000; i += 10) {
    var p = new PairVec3u16Type();

    p.fst[(i)   % 3] = i;
    p.fst[(i+1) % 3] = i+1;
    p.fst[(i+2) % 3] = i+2;

    p.snd[(i)   % 3] = i+3;
    p.snd[(i+1) % 3] = i+4;
    p.snd[(i+2) % 3] = i+5;

    var sum = p.fst[0] + p.fst[1] + p.fst[2];
    assertEq(sum, 3*i + 3);
    sum = p.snd[0] + p.snd[1] + p.snd[2];
    assertEq(sum, 3*i + 12);
  }
}

foo_u16();

vs

setJitCompilerOption("ion.warmup.trigger", 30);

var Vec3u16Type = TypedObject.uint16.array(3);

var PairVec3u16Type = new TypedObject.StructType(({
    fst: Vec3u16Type,
    snd: Vec3u16Type,
}));

function foo_u16() {
    for (let i = 0;i < 5000;i += 10) {
        var p = new PairVec3u16Type();

        p.fst[i % 3] = i;

        p.fst[i + 1 % 3] = i + 1;

        p.fst[i + 2 % 3] = i + 2;

        p.snd[i % 3] = i + 3;

        p.snd[i + 1 % 3] = i + 4;

        p.snd[i + 2 % 3] = i + 5;

        var sum = p.fst[0] + p.fst[1] + p.fst[2];

        assertEq(sum, 3 * i + 3);

        sum = p.snd[0] + p.snd[1] + p.snd[2];

        assertEq(sum, 3 * i + 12);
    }
}

foo_u16();
// Make sure that we can find own, enumerable symbols.
var symbol = Symbol("bad");
var symbol2 = Symbol("good");
var proxy = new Proxy({}, {
    ownKeys() {
        return [symbol, symbol2];
    },
    getOwnPropertyDescriptor(target, name) {
        if (name == symbol)
            return {configurable: true, enumerable: false, value: {}};
        // Only this enumerable symbol should be defined.
        if (name == symbol2)
            return {configurable: true, enumerable: true, value: {}};
        assertEq(true, false);
    },
    get(target, name) {
        // Slightly confusing, but these are the descriptors that defineProperties
        // is going to define on the object.
        if (name == symbol)
            return {configurable: true, value: "bad"};
        if (name == symbol2)
            return {configurable: true, value: "good"};
        assertEq(true, false);
    }
});
assertEq(Object.getOwnPropertySymbols(proxy).length, 2);

var obj = {};
Object.defineProperties(obj, proxy);
assertEq(Object.getOwnPropertySymbols(obj).length, 1);
assertEq(symbol in obj, false);
assertEq(symbol2 in obj, true);
assertEq(obj[symbol2], "good");

vs

var symbol = Symbol("bad");

var symbol2 = Symbol("good");

var proxy = new Proxy(({}), ({
    ownKeys: (function() {
        return [symbol, symbol2,];
    }),
    getOwnPropertyDescriptor: (function(target, name) {
        if (name == symbol) return {
            configurable: true,
            enumerable: false,
            value: {            },
        };

        if (name == symbol2) return {
            configurable: true,
            enumerable: true,
            value: {            },
        };

        assertEq(true, false);
    }),
    get: (function(target, name) {
        if (name == symbol) return {
            configurable: true,
            value: "bad",
        };

        if (name == symbol2) return {
            configurable: true,
            value: "good",
        };

        assertEq(true, false);
    }),
}));

assertEq(Object.getOwnPropertySymbols(proxy).length, 2);

var obj = ({});

Object.defineProperties(obj, proxy);

assertEq(Object.getOwnPropertySymbols(obj).length, 1);

assertEq(symbol in obj, false);

assertEq(symbol2 in obj, true);

assertEq(obj[symbol2], "good");
// |jit-test| error:ReferenceError

// for-of should close iterator even if the exception is once caught by the
// debugger.

var g = newGlobal();
g.parent = this;
g.eval("new Debugger(parent).onExceptionUnwind = function () { };");
// jsfunfuzz-generated
for (var x of []) {};
for (var l of [0]) {
    for (var y = 0; y < 1; y++) {
        g2;
    }
}

vs

var g = newGlobal();

g.parent = this;

g.eval("new Debugger(parent).onExceptionUnwind = function () { };");

for (x of []) { 
    
}

;

for (l of [0,]) {
    for (let y = 0;y < 1;y++) {
        g2;
    }
}
// Tests that NX disallows debuggee execution for all the hooks.

load(libdir + "asserts.js");
load(libdir + "debuggerNXHelper.js");

var g = newGlobal();
var dbg = new Debugger(g);

// Attempts to call g.f without going through an invocation function should
// throw.
g.eval(`
       function f() { }
       var o = {
         get p() { },
         set p(x) { }
       };
       `);

var handlers = [() => { g.f(); },
                () => { g.o.p } ,
                () => { g.o.p = 42; }];

function testHook(hookName) {
  for (var h of handlers) {
    assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
  }
}

testDebuggerHooksNX(dbg, g, testHook);

vs

load(libdir + "asserts.js");

load(libdir + "debuggerNXHelper.js");

var g = newGlobal();

var dbg = new Debugger(g);

g.eval(`
       function f() { }
       var o = {
         get p() { },
         set p(x) { }
       };
       `);

var handlers = [()  => {
    g.f();
}, ()  => {
    g.o.p;
}, ()  => {
    g.o.p = 42;
},];

function testHook(hookName) {
    for (h of handlers) {
        assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
    }
}

testDebuggerHooksNX(dbg, g, testHook);
// |jit-test| skip-if: !('oomTest' in this)

// Test for OOM hitting a breakpoint in a generator.
//
// (The purpose is to test OOM-handling in the code that creates the
// Debugger.Frame object and associates it with the generator object.)

let g = newGlobal();
g.eval(`\
    function* gen(x) {  // line 1
        x++;            // 2
        yield x;        // 3
    }                   // 4
`);

let dbg = new Debugger;

// On OOM in the debugger, propagate it to the debuggee.
dbg.uncaughtExceptionHook = exc => exc === "out of memory" ? {throw: exc} : null;

let gw = dbg.addDebuggee(g);
let script = gw.makeDebuggeeValue(g.gen).script;
let hits = 0;
let handler = {
    hit(frame) {
        hits++;
        print("x=", frame.environment.getVariable("x"));
    }
};
for (let offset of script.getLineOffsets(2))
    script.setBreakpoint(offset, handler);

let result;
oomTest(() => {
    hits = 0;
    result = g.gen(1).next();
}, false);
assertEq(hits, 1);
assertEq(result.done, false);
assertEq(result.value, 2);

vs

let g = newGlobal();

g.eval(`\
    function* gen(x) {  // line 1
        x++;            // 2
        yield x;        // 3
    }                   // 4
`);

let dbg = new Debugger();

dbg.uncaughtExceptionHook = exc => exc === "out of memory" ? {
    throw: exc,
} : null;

let gw = dbg.addDebuggee(g);

let script = gw.makeDebuggeeValue(g.gen).script;

let hits = 0;

let handler = ({
    hit: (function(frame) {
        hits++;
        print("x=", frame.environment.getVariable("x"));
    }),
});

for (offset of script.getLineOffsets(2)) script.setBreakpoint(offset, handler);

let result;

oomTest(()  => {
    hits = 0;
    result = g.gen(1).next();
}, false);

assertEq(hits, 1);

assertEq(result.done, false);

assertEq(result.value, 2);
// tests calling script functions via Debugger.Object.prototype.setProperty
"use strict";

var global = newGlobal();
var dbg = new Debugger(global);
dbg.onDebuggerStatement = onDebuggerStatement;

global.eval(`
const sym = Symbol("a symbol key");

const arr = [];
const obj = {
    set stringNormal(value) {
        this._stringNormal = value;
    },
    set stringAbrupt(value) {
        throw value;
    },

    set objectNormal(value) {
        this._objectNormal = value;
    },
    set objectAbrupt(value) {
        throw value;
    },

    set context(value) {
        this._context = this;
    },

    set 1234(value) {
        this._1234 = value;
    },

    set [sym](value) {
        this._sym = value;
    },

    get getterOnly() {},
    readOnly: "",

    stringProp: "",
    objProp: {},
};
Object.defineProperty(obj, "readOnly", { writable: false });

const objChild = Object.create(obj);
const proxyChild = new Proxy(obj, {});

const testObj = { };
const testChildObj = { };
const testProxyObj = { };

debugger;
`);

function onDebuggerStatement(frame) {
    const { environment } = frame;
    const sym = environment.getVariable("sym");
    const arr = environment.getVariable("arr");
    const obj = environment.getVariable("obj");
    const objChild = environment.getVariable("objChild");
    const proxyChild = environment.getVariable("proxyChild");

    assertEq(arr.setProperty(1, "index 1").return, true);
    assertEq(arr.getProperty(1).return, "index 1");
    assertEq(arr.getProperty("1").return, "index 1");
    assertEq(arr.getProperty(0).return, undefined);
    assertEq(arr.getProperty("length").return, 2);

    assertEq(arr.setProperty("2", "index 2").return, true);
    assertEq(arr.getProperty(2).return, "index 2");
    assertEq(arr.getProperty("2").return, "index 2");
    assertEq(arr.getProperty(0).return, undefined);
    assertEq(arr.getProperty("length").return, 3);

    const testObj = environment.getVariable("testObj");
    assertEq(obj.setProperty("undefined", 123).return, true);
    assertEq(obj.getProperty("undefined").return, 123);
    assertEq(obj.setProperty().return, true);
    assertEq(obj.getProperty("undefined").return, undefined);

    assertEq(obj.setProperty("missing", 42).return, true);
    assertEq(obj.getProperty("missing").return, 42);

    assertEq(obj.setProperty("stringNormal", "a normal value").return, true);
    assertEq(obj.getProperty("_stringNormal").return, "a normal value");
    assertEq(obj.setProperty("stringAbrupt", "an abrupt value").throw, "an abrupt value");

    assertEq(obj.setProperty("objectNormal", testObj).return, true);
    assertEq(obj.getProperty("_objectNormal").return, testObj);
    assertEq(obj.setProperty("objectAbrupt", testObj).throw, testObj);

    assertEq(obj.setProperty("context", "a value").return, true);
    assertEq(obj.getProperty("_context").return, obj);

    assertEq(obj.setProperty(1234, "number value").return, true);
    assertEq(obj.getProperty("_1234").return, "number value");

    assertEq(obj.setProperty(sym, "symbol value").return, true);
    assertEq(obj.getProperty("_sym").return, "symbol value");

    assertEq(obj.setProperty("getterOnly", "a value").return, false);
    assertEq(obj.setProperty("readOnly", "a value").return, false);

    assertEq(obj.setProperty("stringProp", "a normal value").return, true);
    assertEq(obj.getProperty("stringProp").return, "a normal value");

    assertEq(obj.setProperty("objectProp", testObj).return, true);
    assertEq(obj.getProperty("objectProp").return, testObj);

    const testChildObj = environment.getVariable("testChildObj");
    assertEq(objChild.setProperty("undefined", 123).return, true);
    assertEq(objChild.getProperty("undefined").return, 123);
    assertEq(objChild.setProperty().return, true);
    assertEq(objChild.getProperty("undefined").return, undefined);

    assertEq(objChild.setProperty("missing", 42).return, true);
    assertEq(objChild.getProperty("missing").return, 42);

    assertEq(objChild.setProperty("stringNormal", "a normal child value").return, true);
    assertEq(objChild.getProperty("_stringNormal").return, "a normal child value");

    assertEq(objChild.setProperty("stringAbrupt", "an abrupt child value").throw, "an abrupt child value");

    assertEq(objChild.setProperty("objectNormal", testChildObj).return, true);
    assertEq(objChild.getProperty("_objectNormal").return, testChildObj);

    assertEq(objChild.setProperty("objectAbrupt", testChildObj).throw, testChildObj);

    assertEq(objChild.setProperty("context", "a value").return, true);
    assertEq(objChild.getProperty("_context").return, objChild);

    assertEq(objChild.setProperty(1234, "number value").return, true);
    assertEq(objChild.getProperty("_1234").return, "number value");

    assertEq(objChild.setProperty(sym, "symbol value").return, true);
    assertEq(objChild.getProperty("_sym").return, "symbol value");

    assertEq(objChild.setProperty("getterOnly", "a value").return, false);
    assertEq(objChild.setProperty("readOnly", "a value").return, false);

    assertEq(objChild.setProperty("stringProp", "a normal child value").return, true);
    assertEq(objChild.getProperty("stringProp").return, "a normal child value");

    assertEq(objChild.setProperty("objectProp", testChildObj).return, true);
    assertEq(objChild.getProperty("objectProp").return, testChildObj);

    const testProxyObj = environment.getVariable("testProxyObj");
    assertEq(proxyChild.setProperty("undefined", 123).return, true);
    assertEq(proxyChild.getProperty("undefined").return, 123);
    assertEq(proxyChild.setProperty().return, true);
    assertEq(proxyChild.getProperty("undefined").return, undefined);

    assertEq(proxyChild.setProperty("missing", 42).return, true);
    assertEq(proxyChild.getProperty("missing").return, 42);

    assertEq(proxyChild.setProperty("stringNormal", "a normal child value").return, true);
    assertEq(proxyChild.getProperty("_stringNormal").return, "a normal child value");

    assertEq(proxyChild.setProperty("stringAbrupt", "an abrupt child value").throw, "an abrupt child value");

    assertEq(proxyChild.setProperty("objectNormal", testProxyObj).return, true);
    assertEq(proxyChild.getProperty("_objectNormal").return, testProxyObj);

    assertEq(proxyChild.setProperty("objectAbrupt", testProxyObj).throw, testProxyObj);

    assertEq(proxyChild.setProperty("context", "a value").return, true);
    assertEq(proxyChild.getProperty("_context").return, proxyChild);

    assertEq(proxyChild.setProperty(1234, "number value").return, true);
    assertEq(proxyChild.getProperty("_1234").return, "number value");

    assertEq(proxyChild.setProperty(sym, "symbol value").return, true);
    assertEq(proxyChild.getProperty("_sym").return, "symbol value");

    assertEq(proxyChild.setProperty("getterOnly", "a value").return, false);
    assertEq(proxyChild.setProperty("readOnly", "a value").return, false);

    assertEq(proxyChild.setProperty("stringProp", "a normal child value").return, true);
    assertEq(proxyChild.getProperty("stringProp").return, "a normal child value");

    assertEq(proxyChild.setProperty("objectProp", testProxyObj).return, true);
    assertEq(proxyChild.getProperty("objectProp").return, testProxyObj);
};

vs

'use strict';

var global = newGlobal();

var dbg = new Debugger(global);

dbg.onDebuggerStatement = onDebuggerStatement;

global.eval(`
const sym = Symbol("a symbol key");

const arr = [];
const obj = {
    set stringNormal(value) {
        this._stringNormal = value;
    },
    set stringAbrupt(value) {
        throw value;
    },

    set objectNormal(value) {
        this._objectNormal = value;
    },
    set objectAbrupt(value) {
        throw value;
    },

    set context(value) {
        this._context = this;
    },

    set 1234(value) {
        this._1234 = value;
    },

    set [sym](value) {
        this._sym = value;
    },

    get getterOnly() {},
    readOnly: "",

    stringProp: "",
    objProp: {},
};
Object.defineProperty(obj, "readOnly", { writable: false });

const objChild = Object.create(obj);
const proxyChild = new Proxy(obj, {});

const testObj = { };
const testChildObj = { };
const testProxyObj = { };

debugger;
`);

function onDebuggerStatement(frame) {
    const {environment,    } = frame;
    const sym = environment.getVariable("sym");
    const arr = environment.getVariable("arr");
    const obj = environment.getVariable("obj");
    const objChild = environment.getVariable("objChild");
    const proxyChild = environment.getVariable("proxyChild");
    assertEq(arr.setProperty(1, "index 1").return, true);
    assertEq(arr.getProperty(1).return, "index 1");
    assertEq(arr.getProperty("1").return, "index 1");
    assertEq(arr.getProperty(0).return, undefined);
    assertEq(arr.getProperty("length").return, 2);
    assertEq(arr.setProperty("2", "index 2").return, true);
    assertEq(arr.getProperty(2).return, "index 2");
    assertEq(arr.getProperty("2").return, "index 2");
    assertEq(arr.getProperty(0).return, undefined);
    assertEq(arr.getProperty("length").return, 3);
    const testObj = environment.getVariable("testObj");
    assertEq(obj.setProperty("undefined", 123).return, true);
    assertEq(obj.getProperty("undefined").return, 123);
    assertEq(obj.setProperty().return, true);
    assertEq(obj.getProperty("undefined").return, undefined);
    assertEq(obj.setProperty("missing", 42).return, true);
    assertEq(obj.getProperty("missing").return, 42);
    assertEq(obj.setProperty("stringNormal", "a normal value").return, true);
    assertEq(obj.getProperty("_stringNormal").return, "a normal value");
    assertEq(obj.setProperty("stringAbrupt", "an abrupt value").throw, "an abrupt value");
    assertEq(obj.setProperty("objectNormal", testObj).return, true);
    assertEq(obj.getProperty("_objectNormal").return, testObj);
    assertEq(obj.setProperty("objectAbrupt", testObj).throw, testObj);
    assertEq(obj.setProperty("context", "a value").return, true);
    assertEq(obj.getProperty("_context").return, obj);
    assertEq(obj.setProperty(1234, "number value").return, true);
    assertEq(obj.getProperty("_1234").return, "number value");
    assertEq(obj.setProperty(sym, "symbol value").return, true);
    assertEq(obj.getProperty("_sym").return, "symbol value");
    assertEq(obj.setProperty("getterOnly", "a value").return, false);
    assertEq(obj.setProperty("readOnly", "a value").return, false);
    assertEq(obj.setProperty("stringProp", "a normal value").return, true);
    assertEq(obj.getProperty("stringProp").return, "a normal value");
    assertEq(obj.setProperty("objectProp", testObj).return, true);
    assertEq(obj.getProperty("objectProp").return, testObj);
    const testChildObj = environment.getVariable("testChildObj");
    assertEq(objChild.setProperty("undefined", 123).return, true);
    assertEq(objChild.getProperty("undefined").return, 123);
    assertEq(objChild.setProperty().return, true);
    assertEq(objChild.getProperty("undefined").return, undefined);
    assertEq(objChild.setProperty("missing", 42).return, true);
    assertEq(objChild.getProperty("missing").return, 42);
    assertEq(objChild.setProperty("stringNormal", "a normal child value").return, true);
    assertEq(objChild.getProperty("_stringNormal").return, "a normal child value");
    assertEq(objChild.setProperty("stringAbrupt", "an abrupt child value").throw, "an abrupt child value");
    assertEq(objChild.setProperty("objectNormal", testChildObj).return, true);
    assertEq(objChild.getProperty("_objectNormal").return, testChildObj);
    assertEq(objChild.setProperty("objectAbrupt", testChildObj).throw, testChildObj);
    assertEq(objChild.setProperty("context", "a value").return, true);
    assertEq(objChild.getProperty("_context").return, objChild);
    assertEq(objChild.setProperty(1234, "number value").return, true);
    assertEq(objChild.getProperty("_1234").return, "number value");
    assertEq(objChild.setProperty(sym, "symbol value").return, true);
    assertEq(objChild.getProperty("_sym").return, "symbol value");
    assertEq(objChild.setProperty("getterOnly", "a value").return, false);
    assertEq(objChild.setProperty("readOnly", "a value").return, false);
    assertEq(objChild.setProperty("stringProp", "a normal child value").return, true);
    assertEq(objChild.getProperty("stringProp").return, "a normal child value");
    assertEq(objChild.setProperty("objectProp", testChildObj).return, true);
    assertEq(objChild.getProperty("objectProp").return, testChildObj);
    const testProxyObj = environment.getVariable("testProxyObj");
    assertEq(proxyChild.setProperty("undefined", 123).return, true);
    assertEq(proxyChild.getProperty("undefined").return, 123);
    assertEq(proxyChild.setProperty().return, true);
    assertEq(proxyChild.getProperty("undefined").return, undefined);
    assertEq(proxyChild.setProperty("missing", 42).return, true);
    assertEq(proxyChild.getProperty("missing").return, 42);
    assertEq(proxyChild.setProperty("stringNormal", "a normal child value").return, true);
    assertEq(proxyChild.getProperty("_stringNormal").return, "a normal child value");
    assertEq(proxyChild.setProperty("stringAbrupt", "an abrupt child value").throw, "an abrupt child value");
    assertEq(proxyChild.setProperty("objectNormal", testProxyObj).return, true);
    assertEq(proxyChild.getProperty("_objectNormal").return, testProxyObj);
    assertEq(proxyChild.setProperty("objectAbrupt", testProxyObj).throw, testProxyObj);
    assertEq(proxyChild.setProperty("context", "a value").return, true);
    assertEq(proxyChild.getProperty("_context").return, proxyChild);
    assertEq(proxyChild.setProperty(1234, "number value").return, true);
    assertEq(proxyChild.getProperty("_1234").return, "number value");
    assertEq(proxyChild.setProperty(sym, "symbol value").return, true);
    assertEq(proxyChild.getProperty("_sym").return, "symbol value");
    assertEq(proxyChild.setProperty("getterOnly", "a value").return, false);
    assertEq(proxyChild.setProperty("readOnly", "a value").return, false);
    assertEq(proxyChild.setProperty("stringProp", "a normal child value").return, true);
    assertEq(proxyChild.getProperty("stringProp").return, "a normal child value");
    assertEq(proxyChild.setProperty("objectProp", testProxyObj).return, true);
    assertEq(proxyChild.getProperty("objectProp").return, testProxyObj);
}

;
try {
	[0,0].sort(Array.some)
	"".replace(RegExp(), Array.reduce)
} catch (error) {
	if (!(error instanceof TypeError && /^\w is not a function$/.test(error.message)))
		throw error;
}

vs

try {
    [0, 0,].sort(Array.some);

    "".replace(RegExp(), Array.reduce);
} catch (error) {
    if (!error instanceof TypeError && /^\w is not a function$/.test(error.message)) throw error;

}
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap reports an existing own property as
 * non-existent on a non-extensible object
 */
var target = {};
Object.defineProperty(target, 'foo', {
    configurable: true
});
Object.preventExtensions(target);

var handler = { has: () => false };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(function () { 'foo' in p }, TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    configurable: true,
}));

Object.preventExtensions(target);

var handler = ({
    has: ()  => false,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(function() {
    'foo' in p;
}, TypeError);
// |jit-test| error: Error

var g = newGlobal();
g.eval('function f(a) { evaluate("f(" + " - 1);", {newContext: true}); }');
var dbg = new Debugger(g);
var frames = [];
dbg.onEnterFrame = function (frame) {
  if (frames.length == 3)
    return;
  frames.push(frame);
  for (var f of frames)
    f.eval('a').return
};
g.f();

vs

var g = newGlobal();

g.eval('function f(a) { evaluate("f(" + " - 1);", {newContext: true}); }');

var dbg = new Debugger(g);

var frames = [];

dbg.onEnterFrame = (function(frame) {
    if (frames.length == 3) return;

    frames.push(frame);
    for (f of frames) f.eval('a').return;
});

g.f();
// Error handling if parsing a resumption value throws.

var g = newGlobal();
var dbg = Debugger(g);
var rv;
dbg.onDebuggerStatement = stack => rv;
dbg.uncaughtExceptionHook = function (exc) {
    assertEq(exc, "BANG");
    return {return: "recovered"};
};

rv = {get throw() { throw "BANG"; }};
assertEq(g.eval("debugger; false;"), "recovered");

rv = new Proxy({}, {has() { throw "BANG"; }});
assertEq(g.eval("debugger; false;"), "recovered");

vs

var g = newGlobal();

var dbg = Debugger(g);

var rv;

dbg.onDebuggerStatement = stack => rv;

dbg.uncaughtExceptionHook = (function(exc) {
    assertEq(exc, "BANG");
    return {
        return: "recovered",
    };
});

rv = ({
    get throw() {
        throw "BANG";
    },
});

assertEq(g.eval("debugger; false;"), "recovered");

rv = new Proxy(({}), ({
    has: (function() {
        throw "BANG";
    }),
}));

assertEq(g.eval("debugger; false;"), "recovered");
g0 = function(i) {
    this["g"+(i+1)] = g0;
    return "g"+(i+1);
}
function f() {
    a = eval("g0");
    for(var i=0; i<40; i++) {
        a = this[a(i)];
        if (i === 30) {
            gc();
        }
        assertEq(this["g" + i], g0);
    }
}
f();

vs

g0 = (function(i) {
    this["g" + i + 1] = g0;
    return "g" + i + 1;
});

function f() {
    a = eval("g0");
    for (let i = 0;i < 40;i++) {
        a = this[a(i)];

        if (i === 30) {
            gc();
        }

        assertEq(this["g" + i], g0);
    }
}

f();
// assigning to local variables in frame.eval code

var g = newGlobal();
var dbg = new Debugger(g);
dbg.onDebuggerStatement = function (frame) {
    frame.eval("outerarg = 1; outervar = 2; innerarg = 3; innervar = 4;");
};

var result = g.eval("(" + function outer(outerarg) {
        var outervar = 200;
        function inner(innerarg) {
            var innervar = 400;
            debugger;
            return innerarg + innervar;
        }
        var innersum = inner(300);
        return outerarg + outervar + innersum;
    } + ")(100)");

assertEq(result, 10);

vs

var g = newGlobal();

var dbg = new Debugger(g);

dbg.onDebuggerStatement = (function(frame) {
    frame.eval("outerarg = 1; outervar = 2; innerarg = 3; innervar = 4;");
});

var result = g.eval("(" + (function outer(outerarg) {
    var outervar = 200;
    function inner(innerarg) {
        var innervar = 400;
        debugger;;
        return innerarg + innervar;
    }
    var innersum = inner(300);
    return outerarg + outervar + innersum;
}) + ")(100)");

assertEq(result, 10);
// Set iterators produces entries in the order they were inserted.

var set = new Set();
var i;
for (i = 7; i !== 1; i = i * 7 % 1117)
    set.add(i);
assertEq(set.size, 557);

i = 7;
for (var v of set) {
    assertEq(v, i);
    i = i * 7 % 1117;
}
assertEq(i, 1);

vs

var set = new Set();

var i;

for (i = 7;i !== 1;i = i * 7 % 1117) set.add(i);

assertEq(set.size, 557);

i = 7;

for (v of set) {
    assertEq(v, i);

    i = i * 7 % 1117;
}

assertEq(i, 1);
(function() {
    "use strict";
    assertEq(eval("this"), undefined);
})();

vs

(function() {
    'use strict';
    assertEq(eval("this"), undefined);
})();
/*
 * Call the trap with the handler as the this value, the target as the first
 * argument, the name of the property as the second argument, the value as the
 * third argument, and the receiver as the fourth argument
 */
var target = {};
for (var key of ['foo', Symbol.for('quux')]) {
    var handler = { };
    for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
        handler.set = function (target1, name, val, receiver) {
            assertEq(this, handler);
            assertEq(target1, target);
            assertEq(name, key);
            assertEq(val, 'baz');
            assertEq(receiver, p);
            called = true;
        }

        var called = false;
        p[key] = 'baz';
        assertEq(called, true);
    }
}

vs

var target = ({});

for (key of ['foo', Symbol.for('quux'),]) {
    var handler = {    };

    for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
        handler.set = function(target1, name, val, receiver) {
            assertEq(this, handler);
            assertEq(target1, target);
            assertEq(name, key);
            assertEq(val, 'baz');
            assertEq(receiver, p);
            called = true;
        };

        var called = false;

        p[key] = 'baz';

        assertEq(called, true);
    }
}
// |jit-test| allow-oom; skip-if: !('oomAfterAllocations' in this) || helperThreadCount() === 0

lfcode = new Array();
dbg = Debugger();
dbg.onEnterFrame = function() {};
g = newGlobal();
lfcode.push(`
  oomAfterAllocations(100);
  new Number();
  dbg.addDebuggee(g);
`)
file = lfcode.shift();
loadFile(file);
function loadFile(lfVarx) {
  lfGlobal = newGlobal()
  for (lfLocal in this)
      if (!(lfLocal in lfGlobal))
          lfGlobal[lfLocal] = this[lfLocal]
  offThreadCompileScript(lfVarx)
  lfGlobal.runOffThreadScript()
}

vs

lfcode = new Array();

dbg = Debugger();

dbg.onEnterFrame = (function() { });

g = newGlobal();

lfcode.push(`
  oomAfterAllocations(100);
  new Number();
  dbg.addDebuggee(g);
`);

file = lfcode.shift();

loadFile(file);

function loadFile(lfVarx) {
    lfGlobal = newGlobal();
    for (lfLocal in this) if (!lfLocal in lfGlobal) lfGlobal[lfLocal] = this[lfLocal];

    offThreadCompileScript(lfVarx);
    lfGlobal.runOffThreadScript();
}
// Getting a property that exists on an ordinary object
// does not touch a proxy on its proto chain.

load(libdir + "asserts.js");

var angryHandler = new Proxy({}, {
    get(t, id) { throw new Error("angryHandler should not be queried (" + id + ")"); }
});
var angryProto = new Proxy({}, angryHandler);
var obj = Object.create(angryProto, {
    x: {value: 3},
    y: {get: () => 4}
});
assertThrowsInstanceOf(() => obj.z, Error);  // check that angryProto works
assertEq(obj.x, 3);
assertEq(obj.y, 4);

vs

load(libdir + "asserts.js");

var angryHandler = new Proxy(({}), ({
    get: (function(t, id) {
        throw new Error("angryHandler should not be queried (" + id + ")");
    }),
}));

var angryProto = new Proxy(({}), angryHandler);

var obj = Object.create(angryProto, ({
    x: ({
        value: 3,
    }),
    y: ({
        get: ()  => 4,
    }),
}));

assertThrowsInstanceOf(()  => obj.z, Error);

assertEq(obj.x, 3);

assertEq(obj.y, 4);
var path = '';

// trigger off-main-thread compilation
for (var i = 0; i < 11; i++)
  path.substr(-1);

// maybe link to the the result of the off-main-thread compilation.
function load(unsigned) {
  if (unsigned)
    path.substr(-1);
}

(function(global, env) {
  'use asm';
  var load = env.load;
  function _main() {
    var $l1 = 0, $l2 = 0, $l3 = 0;
    do {
      load();
      $l1 = $l1 + 1 | 0;
    } while (($l1 | 0) != 10);
    load(1);
    load(1);
    do {
      load();
      $l2 = $l2 + 1 | 0;
    } while (($l2 | 0) != 1024);
    while (($l3 | 0) < 10000) {
      load(1);
      $l3 = $l3 + 1 | 0;
    }
  }
  return _main;
})({}, { 'load':load })();

vs

var path = '';

for (let i = 0;i < 11;i++) path.substr(-1);

function load(unsigned) {
    if (unsigned) path.substr(-1);

}

(function(global, env) {
    'use asm';
    var load = env.load;
    function _main() {
        var $l1 = 0, $l2 = 0, $l3 = 0;
        do {
            load();

            $l1 = $l1 + 1 | 0;
        } while ($l1 | 0 != 10);
        ;
        load(1);
        load(1);
        do {
            load();

            $l2 = $l2 + 1 | 0;
        } while ($l2 | 0 != 1024);
        ;
        while ($l3 | 0 < 10000) {
            load(1);

            $l3 = $l3 + 1 | 0;
        }
    }
    return _main;
})(({}), ({
    'load': load,
}))();
// new WeakMap(x) throws if x is not iterable (unless x is undefined).

load(libdir + "asserts.js");
var nonIterables = [true, 1, -0, 3.14, NaN, {}, Math, this];
for (let k of nonIterables)
    assertThrowsInstanceOf(function () { new WeakMap(k); }, TypeError);

vs

load(libdir + "asserts.js");

var nonIterables = [true, 1, -0, 3.14, NaN, ({}), Math, this,];

for (k of nonIterables) assertThrowsInstanceOf(function() {
    new WeakMap(k);
}, TypeError);
function a()
{
    "use asm";
    function f()
    {
        return (((((-1) >>> (0+0)) | 0) % 10000) >> (0+0)) | 0;
    }
    return f;
}
assertEq(a()(), -1);

vs

function a() {
    "use asm";
    function f() {
        return -1 >>> 0 + 0 | 0 % 10000 >> 0 + 0 | 0;
    }
    return f;
}

assertEq(a()(), -1);
// getprop, proto and self, 3 shapes

var expected = "22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;";
var actual = '';

var protoB = { a: 11, b: 22, c: 33 };

function B() {
}
B.prototype = protoB;

var protoC = { a: 101, b: 202, c: 303 };

function C() {
}
C.prototype = protoC;

function f() {
  var o1 = new B();
  var o2 = new C();
  var o3 = new C();
  o3.b = 99;
  var oa = [ o1, o2, o3 ];

  for (var i = 0; i < 9; ++i) {
    // Use 3 PICs so we start out with each type in one PIC.
    var i1 = i % 3;
    var i2 = (i+1) % 3;
    var i3 = (i+2) % 3;

    actual += oa[i1].b + ',';
    actual += oa[i2].b + ',';
    actual += oa[i3].b + ';';
  }
}

f();

assertEq(actual, expected);

vs

var expected = "22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;";

var actual = '';

var protoB = ({
    a: 11,
    b: 22,
    c: 33,
});

function B() { }

B.prototype = protoB;

var protoC = ({
    a: 101,
    b: 202,
    c: 303,
});

function C() { }

C.prototype = protoC;

function f() {
    var o1 = new B();
    var o2 = new C();
    var o3 = new C();
    o3.b = 99;
    var oa = [o1, o2, o3,];
    for (let i = 0;i < 9;++i) {
        var i1 = i % 3;

        var i2 = i + 1 % 3;

        var i3 = i + 2 % 3;

        actual += oa[i1].b + ',';

        actual += oa[i2].b + ',';

        actual += oa[i3].b + ';';
    }
}

f();

assertEq(actual, expected);
// Return the trap result
var target = { foo: 'bar' };
var s1 = Symbol("moon"), s2 = Symbol("sun");
target[s1] = "wrong";

var handler = { };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    handler.get = (() => 'baz');
    assertEq(p.foo, 'baz');

    handler.get = (() => undefined);
    assertEq(p.foo, undefined);

    handler.get = (() => s2);
    assertEq(p[s1], s2);
}

vs

var target = ({
    foo: 'bar',
});

var s1 = Symbol("moon"), s2 = Symbol("sun");

target[s1] = "wrong";

var handler = ({});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    handler.get = ()  => 'baz';

    assertEq(p.foo, 'baz');

    handler.get = ()  => undefined;

    assertEq(p.foo, undefined);

    handler.get = ()  => s2;

    assertEq(p[s1], s2);
}
// Comprehensive test of get/setVariable on many kinds of environments and
// bindings.

load(libdir + "asserts.js");

var cases = [
    // global bindings and bindings on the global prototype chain
    "x = VAL; @@",
    "var x = VAL; @@",
    "Object.prototype.x = VAL; @@",

    // let and catch bindings
    "let x = VAL; @@",
    "{ let x = VAL; @@ }",
    "try { throw VAL; } catch (x) { @@ }",
    "try { throw VAL; } catch (x) { @@ }",
    "for (let x of [VAL]) { @@ }",
    "switch (0) { default: let x = VAL; @@ }",

    // arguments
    "function f(x) { @@ } f(VAL);",
    "function f([w, x]) { @@ } f([0, VAL]);",
    "function f({v: x}) { @@ } f({v: VAL});",
    "function f([w, {v: x}]) { @@ } f([0, {v: VAL}]);",

    // bindings in functions
    "function f() { var x = VAL; @@ } f();",
    "function f() { let x = VAL; @@ } f();",
    "function f() { function x() {} x = VAL; @@ } f();",

    // dynamic bindings
    "function f(s) { eval(s); @@ } f('var x = VAL');",
    "var x = VAL; function f(s) { eval('var x = 0;'); eval(s); @@ } f('delete x;');",
    "function f(obj) { with (obj) { @@ } } f({x: VAL});",
    "function f(obj) { with (obj) { @@ } } f(Object.create({x: VAL}));",
    "function f(b) { if (b) { function x(){} } x = VAL; @@ } f(1);",
];

var nextval = 1000;

function test(code, debugStmts, followupStmts) {
    var val = nextval++;
    var hits = 0;

    var g = newGlobal();
    g.eval("function debugMe() { var x = 'wrong-x'; debugger; }");
    g.capture = null;

    var dbg = Debugger(g);
    dbg.onDebuggerStatement = function (frame) {
        if (frame.callee !== null && frame.callee.name == 'debugMe')
            frame = frame.older;
        var env = frame.environment.find("x");
        assertEq(env.getVariable("x"), val)
        assertEq(env.setVariable("x", 'ok'), undefined);
        assertEq(env.getVariable("x"), 'ok');

        // setVariable cannot create new variables.
        assertThrowsInstanceOf(function () { env.setVariable("newVar", 0); }, TypeError);
        hits++;
    };

    code = code.replace("@@", debugStmts);
    if (followupStmts !== undefined)
        code += " " + followupStmts;
    code = code.replace(/VAL/g, uneval(val));
    g.eval(code);
    assertEq(hits, 1);
}

for (var s of cases) {
    // Test triggering the debugger right in the scope in which x is bound.
    test(s, "debugger; assertEq(x, 'ok');");

    // Test calling a function that triggers the debugger.
    test(s, "debugMe(); assertEq(x, 'ok');");

    // Test triggering the debugger from a scope nested in x's scope.
    test(s, "{ let y = 'irrelevant'; (function (z) { { let zz = y; debugger; } })(); } assertEq(x, 'ok');"),

    // Test closing over the variable and triggering the debugger later, after
    // leaving the variable's scope.
    test(s, "capture = {dbg: function () { debugger; }, get x() { return x; }};",
            "assertEq(capture.x, VAL); capture.dbg(); assertEq(capture.x, 'ok');");
}

vs

load(libdir + "asserts.js");

var cases = ["x = VAL; @@", "var x = VAL; @@", "Object.prototype.x = VAL; @@", "let x = VAL; @@", "{ let x = VAL; @@ }", "try { throw VAL; } catch (x) { @@ }", "try { throw VAL; } catch (x) { @@ }", "for (let x of [VAL]) { @@ }", "switch (0) { default: let x = VAL; @@ }", "function f(x) { @@ } f(VAL);", "function f([w, x]) { @@ } f([0, VAL]);", "function f({v: x}) { @@ } f({v: VAL});", "function f([w, {v: x}]) { @@ } f([0, {v: VAL}]);", "function f() { var x = VAL; @@ } f();", "function f() { let x = VAL; @@ } f();", "function f() { function x() {} x = VAL; @@ } f();", "function f(s) { eval(s); @@ } f('var x = VAL');", "var x = VAL; function f(s) { eval('var x = 0;'); eval(s); @@ } f('delete x;');", "function f(obj) { with (obj) { @@ } } f({x: VAL});", "function f(obj) { with (obj) { @@ } } f(Object.create({x: VAL}));", "function f(b) { if (b) { function x(){} } x = VAL; @@ } f(1);",];

var nextval = 1000;

function test(code, debugStmts, followupStmts) {
    var val = nextval++;
    var hits = 0;
    var g = newGlobal();
    g.eval("function debugMe() { var x = 'wrong-x'; debugger; }");
    g.capture = null;
    var dbg = Debugger(g);
    dbg.onDebuggerStatement = function(frame) {
        if (frame.callee !== null && frame.callee.name == 'debugMe') frame = frame.older;

        var env = frame.environment.find("x");
        assertEq(env.getVariable("x"), val);
        assertEq(env.setVariable("x", 'ok'), undefined);
        assertEq(env.getVariable("x"), 'ok');
        assertThrowsInstanceOf(function() {
            env.setVariable("newVar", 0);
        }, TypeError);
        hits++;
    };
    code = code.replace("@@", debugStmts);
    if (followupStmts !== undefined) code += " " + followupStmts;

    code = code.replace(/VAL/g, uneval(val));
    g.eval(code);
    assertEq(hits, 1);
}

for (s of cases) {
    test(s, "debugger; assertEq(x, 'ok');");

    test(s, "debugMe(); assertEq(x, 'ok');");

    test(s, "{ let y = 'irrelevant'; (function (z) { { let zz = y; debugger; } })(); } assertEq(x, 'ok');"), test(s, "capture = {dbg: function () { debugger; }, get x() { return x; }};", "assertEq(capture.x, VAL); capture.dbg(); assertEq(capture.x, 'ok');");
}
// length, various types

var expected = "4,5,44,5,44,4,44,4,5,4,5,44,5,44,4,44,4,5,";
var actual = '';

function f() {
  var a = [ "abcd", [1, 2, 3, 4, 5], { length: 44 } ];

  for (var i = 0; i < 6; ++i) {
    // Use 3 PICs so we start out with each type in one PIC.
    var i1 = i % 3;
    var i2 = (i+1) % 3;
    var i3 = (i+2) % 3;
    actual += a[i1].length + ',';
    actual += a[i2].length + ',';
    actual += a[i3].length + ',';
  }
}

f();

assertEq(actual, expected);

vs

var expected = "4,5,44,5,44,4,44,4,5,4,5,44,5,44,4,44,4,5,";

var actual = '';

function f() {
    var a = ["abcd", [1, 2, 3, 4, 5,], {
        length: 44,
    },];
    for (let i = 0;i < 6;++i) {
        var i1 = i % 3;

        var i2 = i + 1 % 3;

        var i3 = i + 2 % 3;

        actual += a[i1].length + ',';

        actual += a[i2].length + ',';

        actual += a[i3].length + ',';
    }
}

f();

assertEq(actual, expected);
// |jit-test| error: ReferenceError
var t = {};
function r(y) { return t.y = y; }
function g() {
    for (let [x = r(x)] of x) {}
}
r(0);
r(0);
g();

vs

var t = ({});

function r(y) {
    return t.y = y;
}

function g() {
    for ([x = r(x),] of x) { 
        
    }
}

r(0);

r(0);

g();
// Binary: cache/js-dbg-32-30b481fd82f5-linux
// Flags: -j
//
var Native = function(k) {
    var f = k.initialize;
    var d = f;
    var j = function(n, l, o, m) {
        n.prototype[l] = o;
    };
    d.alias = function(n, l, o) {
        n = this.prototype[n]
        return j(this, l, n, o);
    };
    d.implement = function(m, l, o) {
        for (var n in m) {
            j(this, n, m[n], l);
        }
    }
    return d;
};
(function() {
    var a = {
        Array: Array,
        Function: Function,
    };
    for (var h in a) {
        new Native({
            initialize: a[h],
        });
    }
} ());
Array.alias("forEach", "each");
function $merge() {
    var a = Array.slice(arguments);
    a.unshift({});
    return $mixin.apply(null, a);
}
function $mixin(e) {
    for (var d = 1, a = arguments.length; d < a; d++) {
        var b = arguments[d];
        for (var c in b) {
            var g = b[c],
            f = e[c];
            e[c] = f && $type(g) == "object" && $type(f) == "object" ? $mixin(f, g) : $unlink(g);
        }
    }
}
function $type(a) {
    if (a == undefined) {
        return false;
    }
    if (a.$family) {
    }
    return typeof a;
}
function $unlink(c) {
    if ($type(c) == "object") {
        b = {};
    }
    return b;
}
var Window = new Native({
    initialize: function(a) {},
});
Array.implement({
    extend: function(c) {
        return this;
    }
});
Function.implement({
    extend: function(a) {
        for (var b in a) {
            this[b] = a[b];
        }
        return this;
    },
    run: function(a, b) {
        return this.apply(b, a);
    }
});
function Class(b) {
    var a = function() {
        Object.reset(this);
        var c = this.initialize ? this.initialize.apply(this, arguments) : this;
    }.extend(this);
    a.implement(b);
    return a;
}
Object.reset = function(a, c) {
    if (c == null) {
        for (var e in a) {
            Object.reset(a, e);
        }
    }
    switch ($type(a[c])) {
    case "object":
        var d = function() {};
        d.prototype = a[c];
        var b = new d;
        a[c] = Object.reset(b);
    }
    return a;
};
(new Native({initialize: Class})).extend({});
    function wrap(a, b, c) {
        return function() {
            var d = c.apply(this, arguments);
        }.extend({});
    }
Class.implement({
    implement: function(a, d) {
        if ($type(a) == "object") {
            for (var e in a) {
                this.implement(e, a[e]);
            }
        }
        var f = Class.Mutators[a];
        if (f) {
            d = f.call(this, d);
        }
        var c = this.prototype;
        switch ($type(d)) {
        case "function":
            c[a] = wrap(this, a, d);
            break;
        case "object":
            var b = c[a];
            if ($type(b) == "object") {
                $mixin(b, d);
            } else {
                c[a] = $unlink(d);
            }
        }
    }
});
Class.Mutators = {
    Extends: function(a) {
        this.prototype = new a;
    },
    Implements: function(a) {
        a.each(function(b) {
            b = new b;
            this.implement(b);
        },
        this);
    }
};
var Events = new Class({});
var Options = new Class({
    setOptions: function() {
        this.options = $merge.run([this.options].extend(arguments));
    }
});
var Autocompleter = {};
Autocompleter.Base = new Class({
    Implements: [Options, Events],
    options: {},
});
Autocompleter.Ajax = {};
Autocompleter.Ajax.Base = new Class({
    Extends: Autocompleter.Base,
    options: {
        postVar: "value",
        onRequest: function(){},
    }
});
Autocompleter.Ajax.Json = new Class({
    Extends: Autocompleter.Ajax.Base,
});
Autocompleter.JsonP = new Class({
    Extends: Autocompleter.Ajax.Json,
    options: {
        minLength: 1
    },
    initialize: function(el, url, options) {
        this.setOptions({});
    }
});
new Autocompleter.JsonP();

vs

var Native = (function(k) {
    var f = k.initialize;
    var d = f;
    var j = function(n, l, o, m) {
        n.prototype[l] = o;
    };
    d.alias = function(n, l, o) {
        n = this.prototype[n];
        return j(this, l, n, o);
    };
    d.implement = function(m, l, o) {
        for (n in m) {
            j(this, n, m[n], l);
        }
    };
    return d;
});

(function() {
    var a = {
        Array: Array,
        Function: Function,
    };
    for (h in a) {
        new Native({
            initialize: a[h],
        });
    }
})();

Array.alias("forEach", "each");

function $merge() {
    var a = Array.slice(arguments);
    a.unshift({    });
    return $mixin.apply(null, a);
}

function $mixin(e) {
    for (let d = 1, a = arguments.length;d < a;d++) {
        var b = arguments[d];

        for (c in b) {
            var g = b[c], f = e[c];

            e[c] = f && $type(g) == "object" && $type(f) == "object" ? $mixin(f, g) : $unlink(g);
        }
    }
}

function $type(a) {
    if (a == undefined) {
        return false;
    }
    if (a.$family) { 
        
    }
    return typeof a;
}

function $unlink(c) {
    if ($type(c) == "object") {
        b = {        };
    }
    return b;
}

var Window = new Native(({
    initialize: (function(a) { }),
}));

Array.implement(({
    extend: (function(c) {
        return this;
    }),
}));

Function.implement(({
    extend: (function(a) {
        for (b in a) {
            this[b] = a[b];
        }
        return this;
    }),
    run: (function(a, b) {
        return this.apply(b, a);
    }),
}));

function Class(b) {
    var a = function() {
        Object.reset(this);
        var c = this.initialize ? this.initialize.apply(this, arguments) : this;
    }.extend(this);
    a.implement(b);
    return a;
}

Object.reset = (function(a, c) {
    if (c == null) {
        for (e in a) {
            Object.reset(a, e);
        }
    }
    switch ($type(a[c])) {
        case "object":
            var d = function() { };

            d.prototype = a[c];

            var b = new d();

            a[c] = Object.reset(b);

    }
    return a;
});

new Native(({
    initialize: Class,
})).extend(({}));

function wrap(a, b, c) {
    return function() {
        var d = c.apply(this, arguments);
    }.extend({    });
}

Class.implement(({
    implement: (function(a, d) {
        if ($type(a) == "object") {
            for (e in a) {
                this.implement(e, a[e]);
            }
        }
        var f = Class.Mutators[a];
        if (f) {
            d = f.call(this, d);
        }
        var c = this.prototype;
        switch ($type(d)) {
            case "function":
                c[a] = wrap(this, a, d);

            break;

            case "object":
                var b = c[a];

                if ($type(b) == "object") {
                    $mixin(b, d);
                } else {
                    c[a] = $unlink(d);
                }

        }
    }),
}));

Class.Mutators = ({
    Extends: (function(a) {
        this.prototype = new a();
    }),
    Implements: (function(a) {
        a.each(function(b) {
            b = new b();
            this.implement(b);
        }, this);
    }),
});

var Events = new Class(({}));

var Options = new Class(({
    setOptions: (function() {
        this.options = $merge.run([this.options,].extend(arguments));
    }),
}));

var Autocompleter = ({});

Autocompleter.Base = new Class(({
    Implements: [Options, Events,],
    options: ({    }),
}));

Autocompleter.Ajax = ({});

Autocompleter.Ajax.Base = new Class(({
    Extends: Autocompleter.Base,
    options: ({
        postVar: "value",
        onRequest: (function() { }),
    }),
}));

Autocompleter.Ajax.Json = new Class(({
    Extends: Autocompleter.Ajax.Base,
}));

Autocompleter.JsonP = new Class(({
    Extends: Autocompleter.Ajax.Json,
    options: ({
        minLength: 1,
    }),
    initialize: (function(el, url, options) {
        this.setOptions({        });
    }),
}));

new Autocompleter.JsonP();
// Forward to the target if the trap is not defined
var proto = Object.create(null, {
    'foo': {
        configurable: true
    }
});
var descs = {
    'bar': {
        configurable: true
    }
};
descs[Symbol.for("quux")] = {configurable: true};
var target = Object.create(proto, descs);

for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
    assertEq(({}).hasOwnProperty.call(p, 'foo'), false);
    assertEq(({}).hasOwnProperty.call(p, 'bar'), true);
    assertEq(({}).hasOwnProperty.call(p, 'quux'), false);
    assertEq(({}).hasOwnProperty.call(p, Symbol('quux')), false);
    assertEq(({}).hasOwnProperty.call(p, 'Symbol(quux)'), false);
    assertEq(({}).hasOwnProperty.call(p, Symbol.for('quux')), true);
}

// Make sure only the getOwnPropertyDescriptor trap is called, and not the has
// trap.
var called;
var handler = { getOwnPropertyDescriptor: function () { called = true; },
                has: function () { assertEq(false, true, "has trap must not be called"); }
              }

for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy]) {
    called = false;
    assertEq(({}).hasOwnProperty.call(p, 'foo'), false);
    assertEq(called, true);
}

vs

var proto = Object.create(null, ({
    'foo': ({
        configurable: true,
    }),
}));

var descs = ({
    'bar': ({
        configurable: true,
    }),
});

descs[Symbol.for("quux")] = ({
    configurable: true,
});

var target = Object.create(proto, descs);

for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy,]) {
    assertEq({    }.hasOwnProperty.call(p, 'foo'), false);

    assertEq({    }.hasOwnProperty.call(p, 'bar'), true);

    assertEq({    }.hasOwnProperty.call(p, 'quux'), false);

    assertEq({    }.hasOwnProperty.call(p, Symbol('quux')), false);

    assertEq({    }.hasOwnProperty.call(p, 'Symbol(quux)'), false);

    assertEq({    }.hasOwnProperty.call(p, Symbol.for('quux')), true);
}

var called;

var handler = ({
    getOwnPropertyDescriptor: (function() {
        called = true;
    }),
    has: (function() {
        assertEq(false, true, "has trap must not be called");
    }),
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) {
    called = false;

    assertEq({    }.hasOwnProperty.call(p, 'foo'), false);

    assertEq(called, true);
}
// Debugger should be notified of scripts created with cloneAndExecuteScript.

var g = newGlobal();
var g2 = newGlobal();
var dbg = new Debugger(g, g2);
var log = '';

dbg.onNewScript = function (evalScript) {
  log += 'e';

  dbg.onNewScript = function (clonedScript) {
    log += 'c';
    clonedScript.setBreakpoint(0, {
      hit(frame) {
        log += 'b';
        assertEq(frame.script, clonedScript);
      }
    });
  };
};

dbg.onDebuggerStatement = function (frame) {
  log += 'd';
};

assertEq(log, '');
g.cloneAndExecuteScript("debugger; // nee", g2);
assertEq(log, 'ecbd');

vs

var g = newGlobal();

var g2 = newGlobal();

var dbg = new Debugger(g, g2);

var log = '';

dbg.onNewScript = (function(evalScript) {
    log += 'e';
    dbg.onNewScript = function(clonedScript) {
        log += 'c';
        clonedScript.setBreakpoint(0, {
            hit: function(frame) {
                log += 'b';
                assertEq(frame.script, clonedScript);
            },
        });
    };
});

dbg.onDebuggerStatement = (function(frame) {
    log += 'd';
});

assertEq(log, '');

g.cloneAndExecuteScript("debugger; // nee", g2);

assertEq(log, 'ecbd');
function f(x, [y]) {}
f(0, []);
// jsfunfuzz-generated
let i = 0;
for (var z of [0, 0, 0]) {
    verifyprebarriers();
}

vs

function f(x, [y,]) { }

f(0, []);

let i = 0;

for (z of [0, 0, 0,]) {
    verifyprebarriers();
}
// |jit-test| skip-if: !this.SharedArrayBuffer || !isAsmJSCompilationAvailable()

Random = {
    weighted: function(wa) {
        var a = [];
        for (var i = 0; i < wa.length; ++i) {
            for (var j = 0; j < wa[i]; ++j) {}
        }
    }
}
s = (function() {
    Random.weighted([{
            n() {}
        }, {
            n() {}
        }, {
            n() {}
        }, {
            w: 5,
            n() {}
        }
    ])
})()
var builtinObjectNames = [];
(function() {
    function exploreDeeper(a, a) {
        var s = Object.getOwnPropertyNames(a)
        for (var j = 0; j < s.length; ++j) {
            if (typeof h == "" && n != "") {}
        }
        builtinObjectNames.push()
    }
    exploreDeeper(Math, "")
})(this, false)
r = autoExpr(Random.weighted([]));
r = autoExpr(Random.weighted([]));
(Random.weighted([]));
r = (Random.weighted([]))
v = autoExpr(Random.weighted([]), true);
r = autoExpr(Random.weighted([{
        n() {}
    }
]), true)
function autoExpr() {}
function makeStatement() {}
s = Random.weighted([{
        n() {}
    }
])
a = Random.weighted([{}, {}, {}, {}, {}, {
        n() {}
    }
])
a = Random.weighted([{
        n() {}
    }, {}, {}
])
var recursiveFunctions = [{
        text: "(function(){{}})"
    }, {
        text: "(function(){if(0){}(1)})",
        n() {}
    }, {
        text: "(function(){t:[]()})",
        n() {}
    }, {
        text: "(function(){g()})",
        n() {}
    }
];
(function s() {
    for (var i = 0; i < recursiveFunctions.length; ++i) {
        a = recursiveFunctions[i];
        var text = a.text
        a = eval(text.replace(/@/, ""))
    }
    function g() {}
    s = Random.weighted([{
            w: 1,
            n() {}
        }, {
            n() {}
        }, //
        {
            n() {}
        }, //
        {
            n() {}
        }, {
            w: 0,
            n() {}
        }, {
            n() {}
        }, {
            n() {}
        }, {
            w: 1,
            n() {}
        }, {
            w: makeStatement
        }, {
            w: 5
        }
    ])
    t = function() {}
    function c() {}
})()
function testMathyFunction(f, inputs) {
    var r = [];
    for (var j = 0; j < inputs.length; ++j) {
        for (var k = 0; k < inputs.length; ++k) {
            try {
                f(inputs[j])
            } catch (e) {}
        }
    }
    uneval([])
}
mathy2 = (function(stdlib, foreign, heap) {
    "use asm";
    var Float32ArrayView = new stdlib.Float32Array(heap)
        function f(i0) {
            i0 = i0 | 0;
            (Float32ArrayView[-i0 >> 2]) = 1.
        }
    return f
})(this, {
}, new SharedArrayBuffer(4096))
testMathyFunction(mathy2, [-0])
mathy5 = (function(y) {
    ((function() {})(mathy2(y)()))
})
testMathyFunction(mathy5, [Math.PI])

vs

Random = ({
    weighted: (function(wa) {
        var a = [];
        for (let i = 0;i < wa.length;++i) {
            for (let j = 0;j < wa[i];++j) { 
                
            }
        }
    }),
});

s = (function() {
    Random.weighted([{
        n: function() { },
    }, {
        n: function() { },
    }, {
        n: function() { },
    }, {
        w: 5,
        n: function() { },
    },]);
})();

var builtinObjectNames = [];

(function() {
    function exploreDeeper(a, a) {
        var s = Object.getOwnPropertyNames(a);
        for (let j = 0;j < s.length;++j) {
            if (typeof h == "" && n != "") { 
                
            }
        }
        builtinObjectNames.push();
    }
    exploreDeeper(Math, "");
})(this, false);

r = autoExpr(Random.weighted([]));

r = autoExpr(Random.weighted([]));

Random.weighted([]);

r = Random.weighted([]);

v = autoExpr(Random.weighted([]), true);

r = autoExpr(Random.weighted([({
    n: (function() { }),
}),]), true);

function autoExpr() { }

function makeStatement() { }

s = Random.weighted([({
    n: (function() { }),
}),]);

a = Random.weighted([({}), ({}), ({}), ({}), ({}), ({
    n: (function() { }),
}),]);

a = Random.weighted([({
    n: (function() { }),
}), ({}), ({}),]);

var recursiveFunctions = [({
    text: "(function(){{}})",
}), ({
    text: "(function(){if(0){}(1)})",
    n: (function() { }),
}), ({
    text: "(function(){t:[]()})",
    n: (function() { }),
}), ({
    text: "(function(){g()})",
    n: (function() { }),
}),];

(function s() {
    for (let i = 0;i < recursiveFunctions.length;++i) {
        a = recursiveFunctions[i];

        var text = a.text;

        a = eval(text.replace(/@/, ""));
    }
    function g() { }
    s = Random.weighted([{
        w: 1,
        n: function() { },
    }, {
        n: function() { },
    }, {
        n: function() { },
    }, {
        n: function() { },
    }, {
        w: 0,
        n: function() { },
    }, {
        n: function() { },
    }, {
        n: function() { },
    }, {
        w: 1,
        n: function() { },
    }, {
        w: makeStatement,
    }, {
        w: 5,
    },]);
    t = function() { };
    function c() { }
})();

function testMathyFunction(f, inputs) {
    var r = [];
    for (let j = 0;j < inputs.length;++j) {
        for (let k = 0;k < inputs.length;++k) {
            try {
                f(inputs[j]);
            } catch (e) { 
                
            }
        }
    }
    uneval([]);
}

mathy2 = (function(stdlib, foreign, heap) {
    "use asm";
    var Float32ArrayView = new stdlib.Float32Array(heap);
    function f(i0) {
        i0 = i0 | 0;
        Float32ArrayView[-i0 >> 2] = 1.;
    }
    return f;
})(this, ({}), new SharedArrayBuffer(4096));

testMathyFunction(mathy2, [-0,]);

mathy5 = (function(y) {
    function() { }(mathy2(y)());
});

testMathyFunction(mathy5, [Math.PI,]);
// Binary: cache/js-dbg-32-33b05dd43cd4-linux
// Flags: -m
//
for (let x in []) {
  t(x !== x)
}

vs

for (x in []) {
    t(x !== x);
}
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap skips an existing own enumerable property on a
 * non-extensible object
 */
var target = {};
Object.defineProperty(target, 'foo', {
    enumerable: true,
    configurable: true
});
Object.preventExtensions(target);

var handler = { ownKeys: () => [] };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.keys(p), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.defineProperty(target, 'foo', ({
    enumerable: true,
    configurable: true,
}));

Object.preventExtensions(target);

var handler = ({
    ownKeys: ()  => [],
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.keys(p), TypeError);
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */
function testProperty(i)
{
  actual = obj[String(i)];
}

var obj = {};
var index = [null, 1073741824, 1073741825];
for (var j in index)
  testProperty(index[j]);

vs

function testProperty(i) {
    actual = obj[String(i)];
}

var obj = ({});

var index = [null, 1073741824, 1073741825,];

for (j in index) testProperty(index[j]);
load(libdir + 'asserts.js');

function test() {
  let obj = {
    toSource() {
      throw 1;
    }
  };
  assertTypeErrorMessage(() => { ctypes.double().value = obj; },
                         "can't convert <<error converting value to string>> to the type double");
}

if (typeof ctypes === "object")
  test();

vs

load(libdir + 'asserts.js');

function test() {
    let obj = {
        toSource: function() {
            throw 1;
        },
    };
    assertTypeErrorMessage(()  => {
        ctypes.double().value = obj;
    }, "can't convert <<error converting value to string>> to the type double");
}

if (typeof ctypes === "object") test();

// Getting a property O.X, inherited from a transparent cross-compartment wrapper W
// that wraps a Proxy P.

var g = newGlobal();
var target = {}
var P = new Proxy(target, {
    get(t, id, r) {
        assertEq(t, target);
        assertEq(id, "X");
        assertEq(r, wO);
        return "vega";
    }
});

g.W = P;
g.eval("var O = Object.create(W);");
var wO = g.O;
assertEq(g.eval("O.X"), "vega");

vs

var g = newGlobal();

var target = ({});

var P = new Proxy(target, ({
    get: (function(t, id, r) {
        assertEq(t, target);
        assertEq(id, "X");
        assertEq(r, wO);
        return "vega";
    }),
}));

g.W = P;

g.eval("var O = Object.create(W);");

var wO = g.O;

assertEq(g.eval("O.X"), "vega");
// Return undefined if the trap returns undefined
var target = {};
Object.defineProperty(target, 'foo', {
    configurable: true
});

var handler = { getOwnPropertyDescriptor: () => undefined };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertEq(Object.getOwnPropertyDescriptor(p, 'foo'), undefined);

vs

var target = ({});

Object.defineProperty(target, 'foo', ({
    configurable: true,
}));

var handler = ({
    getOwnPropertyDescriptor: ()  => undefined,
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertEq(Object.getOwnPropertyDescriptor(p, 'foo'), undefined);
// Ensure the correct frame is passed to exception unwind hooks.
var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("(" + function () {
    frames = [];
    var dbg = Debugger(debuggeeGlobal);
    dbg.onEnterFrame = function(frame) {
	frames.push(frame);
    };
    dbg.onExceptionUnwind = function(frame) {
	assertEq(frames.indexOf(frame), frames.length - 1);
	frames.pop();
	assertEq(frame, dbg.getNewestFrame());
    }
} + ")()");

function f(n) {
    debugger;
    n--;
    if (n > 0) {
        f(n);
    } else {
	assertEq(g.frames.length, 10);
        throw "fit";
    }
}
try {
    f(10);
    assertEq(0, 1);
} catch (e) {
    assertEq(e, "fit");
}
assertEq(g.frames.length, 0);

vs

var g = newGlobal();

g.debuggeeGlobal = this;

g.eval("(" + (function() {
    frames = [];
    var dbg = Debugger(debuggeeGlobal);
    dbg.onEnterFrame = function(frame) {
        frames.push(frame);
    };
    dbg.onExceptionUnwind = function(frame) {
        assertEq(frames.indexOf(frame), frames.length - 1);
        frames.pop();
        assertEq(frame, dbg.getNewestFrame());
    };
}) + ")()");

function f(n) {
    debugger;;
    n--;
    if (n > 0) {
        f(n);
    } else {
        assertEq(g.frames.length, 10);

        throw "fit";
    }
}

try {
    f(10);

    assertEq(0, 1);
} catch (e) {
    assertEq(e, "fit");
}

assertEq(g.frames.length, 0);
// When assigning to an object with a proxy is on the prototype chain,
// the proxy's set handler is called.

var C = {};
var B = new Proxy(C, {
    get() { throw "FAIL"; },
    getOwnPropertyDescriptor() { throw "FAIL"; },
    has() { throw "FAIL"; },
    defineProperty() { throw "FAIL"; },
    set(target, id, value, receiver) {
        hits++;
        assertEq(target, C);
        assertEq(id, "x");
        assertEq(value, 3);
        assertEq(receiver, A);
        return true;
    }
});
var A = Object.create(B);

var hits = 0;
A.x = 3;
assertEq(hits, 1);

vs

var C = ({});

var B = new Proxy(C, ({
    get: (function() {
        throw "FAIL";
    }),
    getOwnPropertyDescriptor: (function() {
        throw "FAIL";
    }),
    has: (function() {
        throw "FAIL";
    }),
    defineProperty: (function() {
        throw "FAIL";
    }),
    set: (function(target, id, value, receiver) {
        hits++;
        assertEq(target, C);
        assertEq(id, "x");
        assertEq(value, 3);
        assertEq(receiver, A);
        return true;
    }),
}));

var A = Object.create(B);

var hits = 0;

A.x = 3;

assertEq(hits, 1);
// tests calling script functions via Debugger.Object.prototype.getProperty
// to see if they trigger debugger traps
"use strict";

var global = newGlobal();
var dbg = new Debugger(global);
dbg.onDebuggerStatement = onDebuggerStatement;

let obj;
global.eval(`
const obj = {
    get prop() {
        debugger;
        return 42;
    }
};

debugger;
`);


function onDebuggerStatement(frame) {
    dbg.onDebuggerStatement = onDebuggerStatementGetter;

    obj = frame.environment.getVariable("obj");
}

let debuggerRan = false;

assertEq(obj.getProperty("prop").return, 42);
assertEq(debuggerRan, true);

function onDebuggerStatementGetter(frame) {
    debuggerRan = true;
}

vs

'use strict';

var global = newGlobal();

var dbg = new Debugger(global);

dbg.onDebuggerStatement = onDebuggerStatement;

let obj;

global.eval(`
const obj = {
    get prop() {
        debugger;
        return 42;
    }
};

debugger;
`);

function onDebuggerStatement(frame) {
    dbg.onDebuggerStatement = onDebuggerStatementGetter;
    obj = frame.environment.getVariable("obj");
}

let debuggerRan = false;

assertEq(obj.getProperty("prop").return, 42);

assertEq(debuggerRan, true);

function onDebuggerStatementGetter(frame) {
    debuggerRan = true;
}
/* Handle recompilation of arithmetic operations, and on-stack int -> double conversion. */

function add(x, y)
{
  var z = x + y;
  assertEq(z, 2147483732);
  assertEq(z - 10, 2147483722);
}
add(0x7ffffff0, 100);

function mul(x, y)
{
  var z = x * y;
  assertEq(z, 4294967264);
}
mul(0x7ffffff0, 2);

function div1(x, y)
{
  var z = x / y;
  assertEq(z + 10, 20);
}
div1(100, 10);

function div2(x, y)
{
  var z = x / y;
  assertEq(z + 10, 20.5);
}
div2(105, 10);

function uncopy(x, y)
{
  var q = x;
  x += y;
  q++;
  assertEq(q, 2147483633);
  assertEq(x, 2147483732);
}
uncopy(0x7ffffff0, 100);

function addmore(x, y)
{
  var q = (x + 10) + (x + y);
  assertEq(q, 4294967374);
  x = q;
}
addmore(0x7ffffff0, 100);

vs

function add(x, y) {
    var z = x + y;
    assertEq(z, 2147483732);
    assertEq(z - 10, 2147483722);
}

add(0x7ffffff0, 100);

function mul(x, y) {
    var z = x * y;
    assertEq(z, 4294967264);
}

mul(0x7ffffff0, 2);

function div1(x, y) {
    var z = x / y;
    assertEq(z + 10, 20);
}

div1(100, 10);

function div2(x, y) {
    var z = x / y;
    assertEq(z + 10, 20.5);
}

div2(105, 10);

function uncopy(x, y) {
    var q = x;
    x += y;
    q++;
    assertEq(q, 2147483633);
    assertEq(x, 2147483732);
}

uncopy(0x7ffffff0, 100);

function addmore(x, y) {
    var q = x + 10 + x + y;
    assertEq(q, 4294967374);
    x = q;
}

addmore(0x7ffffff0, 100);
// Frame properties and methods work in generator-resuming onEnterFrame events.
// Also tests onPop events, for good measure.

let g = newGlobal();
g.eval(`\
    function* gen(lo, hi) {
        var a = 1/2;
        yield a;
        yield a * a;
    }
`);
let dbg = new Debugger;
let gw = dbg.addDebuggee(g);

let hits = 0;
let savedScript = null;
let savedEnv = null;
let savedOffsets = new Set;

function check(frame) {
    assertEq(frame.type, "call");
    assertEq(frame.constructing, false);
    assertEq(frame.callee, gw.makeDebuggeeValue(g.gen));

    // `arguments` elements don't work in resumed generator frames,
    // because generators don't keep the arguments around.
    // However, some of this is initialized when the frame.arguments object is
    // created, so if they are created during the first onEnterFrame or onPop
    // event, the properties exist, and those events can also see the values.
    assertEq(frame.arguments.length, args.length);
    for (var i = 0; i < args.length; i++) {
        assertEq(frame.arguments.hasOwnProperty(i), true);

        if (hits < 2)
            assertEq(frame.arguments[i], gw.makeDebuggeeValue(args[i]), `arguments[${i}]`);
        else
            assertEq(frame.arguments[i], undefined);
    }

    if (savedEnv === null) {
        savedEnv = frame.environment;
        assertEq(savedScript, null);
        savedScript = frame.script;
    } else {
        assertEq(frame.environment, savedEnv);
        assertEq(frame.script, savedScript);
    }
    let a_expected = hits < 3 ? undefined : 1/2;
    assertEq(savedEnv.getVariable("a"), a_expected);

    assertEq(frame.generator, true);
    assertEq(frame.live, true);

    let pc = frame.offset;
    assertEq(savedOffsets.has(pc), false);
    savedOffsets.add(pc);

    assertEq(frame.older, null);
    assertEq(frame.this, gw);
    assertEq(typeof frame.implementation, "string");

    // And the moment of truth:
    assertEq(frame.eval("2 + 2").return, 4);
    assertEq(frame.eval("a").return, a_expected);
    assertEq(frame.eval("if (a !== undefined) { assertEq(a < (lo + hi) / 2, true); } 7;").return, 7);
}

dbg.onEnterFrame = frame => {
    if (frame.type === "eval")
        return;
    check(frame);
    hits++;
    frame.onPop = completion => {
        check(frame);
        hits++;
    };
};

// g.gen ignores the arguments passed to it, but we use them to test
// frame.arguments.
let args = [0, 10, g, dbg];
for (let v of g.gen(...args)) {}
assertEq(hits, 8);

vs

let g = newGlobal();

g.eval(`\
    function* gen(lo, hi) {
        var a = 1/2;
        yield a;
        yield a * a;
    }
`);

let dbg = new Debugger();

let gw = dbg.addDebuggee(g);

let hits = 0;

let savedScript = null;

let savedEnv = null;

let savedOffsets = new Set();

function check(frame) {
    assertEq(frame.type, "call");
    assertEq(frame.constructing, false);
    assertEq(frame.callee, gw.makeDebuggeeValue(g.gen));
    assertEq(frame.arguments.length, args.length);
    for (let i = 0;i < args.length;i++) {
        assertEq(frame.arguments.hasOwnProperty(i), true);

        if (hits < 2) assertEq(frame.arguments[i], gw.makeDebuggeeValue(args[i]), `arguments[${i}]`);
 else assertEq(frame.arguments[i], undefined);

    }
    if (savedEnv === null) {
        savedEnv = frame.environment;

        assertEq(savedScript, null);

        savedScript = frame.script;
    } else {
        assertEq(frame.environment, savedEnv);

        assertEq(frame.script, savedScript);
    }
    let a_expected = hits < 3 ? undefined : 1 / 2;
    assertEq(savedEnv.getVariable("a"), a_expected);
    assertEq(frame.generator, true);
    assertEq(frame.live, true);
    let pc = frame.offset;
    assertEq(savedOffsets.has(pc), false);
    savedOffsets.add(pc);
    assertEq(frame.older, null);
    assertEq(frame.this, gw);
    assertEq(typeof frame.implementation, "string");
    assertEq(frame.eval("2 + 2").return, 4);
    assertEq(frame.eval("a").return, a_expected);
    assertEq(frame.eval("if (a !== undefined) { assertEq(a < (lo + hi) / 2, true); } 7;").return, 7);
}

dbg.onEnterFrame = frame => {
    if (frame.type === "eval") return;

    check(frame);
    hits++;
    frame.onPop = completion => {
        check(frame);
        hits++;
    };
};

let args = [0, 10, g, dbg,];

for (v of g.gen(...args)) { 
    
}

assertEq(hits, 8);
// Tests that earlier try notes don't interfere with later exception handling.

var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("(" + function () {
  dbg = new Debugger(debuggeeGlobal);
} + ")();");
var myObj = { p1: 'a', }
try {
  with(myObj) {
    do {
      throw value;
    } while(false);
  }
} catch(e) {
  // The above is expected to throw.
}

try {
  if(!(p1 === 1)) { }
} catch (e) {
  // The above is expected to throw.
}

vs

var g = newGlobal();

g.debuggeeGlobal = this;

g.eval("(" + (function() {
    dbg = new Debugger(debuggeeGlobal);
}) + ")();");

var myObj = ({
    p1: 'a',
});

try {
    with (myObj) {
        do {
            throw value;
        } while (false);

        ;
    }
} catch (e) { 
    
}

try {
    if (!p1 === 1) { 
        
    }
} catch (e) { 
    
}
var IsPossiblyWrappedTypedArray = getSelfHostedValue("IsPossiblyWrappedTypedArray");

var declareSamples = `
    var allTypedArraySamples = [
        { value: new Int8Array(1), expected: true },
        { value: new Uint8Array(1), expected: true },
        { value: new Int16Array(1), expected: true },
        { value: new Uint16Array(1), expected: true },
        { value: new Int32Array(1), expected: true },
        { value: new Uint32Array(1), expected: true },
        { value: new Float32Array(1), expected: true },
        { value: new Float64Array(1), expected: true },
        { value: new Uint8ClampedArray(1), expected: true }
    ];

    var allObjectSamples = [
        { value: new Array(1), expected: false },
        { value: {}, expected: false },
        { value: { length: 1 }, expected: false }
    ];
`;

// Create a new global to wrap with cross compartment wrappers.
var g = newGlobal();
evaluate(declareSamples)
g.evaluate(declareSamples);

var assertCode = `function (value, expected) {
    assertEq(IsPossiblyWrappedTypedArray(value), expected);
    return inIon();
}`;

function checkSamples(samples) {
    // Create the assert function anew every run so as not to share JIT code,
    // type information, etc.
    var assert = new Function(`return (${assertCode})`)();

    // Prevent Ion compilation of this function so that we don't freeze the
    // sample array's type.  If we did, IonBuilder's typed-array-length inlining
    // would always see a Mixed state, preventing IsPossiblyWrappedTypedArray
    // from being inlined.
    with ({}) {};

    do {
        // spinInJit is used to ensure that we at least test all elements in the
        // sample vector while running a compiled version of the assert
        // function.
        var spinInJit = true;
        for (var i = 0; i < samples.length; i++) {
            var e = samples[i];
            if (!e) continue;
            spinInJit = spinInJit && assert(e.value, e.expected);
        }
    } while(!spinInJit);
}

// Check a mix of samples from each type.
function test(a, b, c, d) {
    var samples = [
        a == -1 ? null : allTypedArraySamples[a],
        b == -1 ? null : allObjectSamples[b],
        c == -1 ? null : g.allTypedArraySamples[c],
        d == -1 ? null : g.allObjectSamples[d],
    ];

    checkSamples(samples);
}

// Check all samples.
checkSamples(allTypedArraySamples);
checkSamples(allObjectSamples);
checkSamples(g.allTypedArraySamples);
checkSamples(g.allObjectSamples);

// Check combinations mixing 2 elements from different types.
test(-1, -1,  0,  0);
test(-1,  0, -1,  0);
test(-1,  0,  0, -1);
test( 0, -1, -1,  0);
test( 0, -1,  0, -1);
test( 0,  0, -1, -1);
test( 0,  0, -1,  0);

// Check combinations mixing 3 elements from different types.
test(-1,  0,  0,  0);
test( 0, -1,  0,  0);
test( 0,  0, -1,  0);
test( 0,  0,  0, -1);

// Check combinations mixing 4 elements from different types.
test( 0,  0,  0,  0);

vs

var IsPossiblyWrappedTypedArray = getSelfHostedValue("IsPossiblyWrappedTypedArray");

var declareSamples = `
    var allTypedArraySamples = [
        { value: new Int8Array(1), expected: true },
        { value: new Uint8Array(1), expected: true },
        { value: new Int16Array(1), expected: true },
        { value: new Uint16Array(1), expected: true },
        { value: new Int32Array(1), expected: true },
        { value: new Uint32Array(1), expected: true },
        { value: new Float32Array(1), expected: true },
        { value: new Float64Array(1), expected: true },
        { value: new Uint8ClampedArray(1), expected: true }
    ];

    var allObjectSamples = [
        { value: new Array(1), expected: false },
        { value: {}, expected: false },
        { value: { length: 1 }, expected: false }
    ];
`;

var g = newGlobal();

evaluate(declareSamples);

g.evaluate(declareSamples);

var assertCode = `function (value, expected) {
    assertEq(IsPossiblyWrappedTypedArray(value), expected);
    return inIon();
}`;

function checkSamples(samples) {
    var assert = new Function(`return (${assertCode})`)();
    with ({    }) { 
        
    }
    ;
    do {
        var spinInJit = true;

        for (let i = 0;i < samples.length;i++) {
            var e = samples[i];

            if (!e) continue;


            spinInJit = spinInJit && assert(e.value, e.expected);
        }
    } while (!spinInJit);
    ;
}

function test(a, b, c, d) {
    var samples = [a == -1 ? null : allTypedArraySamples[a], b == -1 ? null : allObjectSamples[b], c == -1 ? null : g.allTypedArraySamples[c], d == -1 ? null : g.allObjectSamples[d],];
    checkSamples(samples);
}

checkSamples(allTypedArraySamples);

checkSamples(allObjectSamples);

checkSamples(g.allTypedArraySamples);

checkSamples(g.allObjectSamples);

test(-1, -1, 0, 0);

test(-1, 0, -1, 0);

test(-1, 0, 0, -1);

test(0, -1, -1, 0);

test(0, -1, 0, -1);

test(0, 0, -1, -1);

test(0, 0, -1, 0);

test(-1, 0, 0, 0);

test(0, -1, 0, 0);

test(0, 0, -1, 0);

test(0, 0, 0, -1);

test(0, 0, 0, 0);
load(libdir + "asserts.js");
var oldOpts = getJitCompilerOptions();
for (var k in oldOpts)
    setJitCompilerOption(k, oldOpts[k]);
var newOpts = getJitCompilerOptions();
assertDeepEq(oldOpts, newOpts);

vs

load(libdir + "asserts.js");

var oldOpts = getJitCompilerOptions();

for (k in oldOpts) setJitCompilerOption(k, oldOpts[k]);

var newOpts = getJitCompilerOptions();

assertDeepEq(oldOpts, newOpts);
// |jit-test| skip-if: helperThreadCount() === 0

load(libdir + "asserts.js");

function BigInteger(a, b, c) {}
function montConvert(x) {
    var r = new BigInteger(null);
    return r;
}
var ba = new Array();
a = new BigInteger(ba);
g = montConvert(a);
var lfGlobal = newGlobal();
for (lfLocal in this) {
    if (!(lfLocal in lfGlobal)) {
        lfGlobal[lfLocal] = this[lfLocal];
    }
}
lfGlobal.offThreadCompileScript(`
  var dbg = new Debugger(g);
  dbg.onEnterFrame = function (frame) {
    var frameThis = frame.this;
  }
`);
lfGlobal.runOffThreadScript();
assertThrowsInstanceOf(test, ReferenceError);
function test() {
    function check(fun, msg, todo) {
        success = fun();
    }
    check(() => Object.getPrototypeOf(view) == Object.getPrototypeOf(simple));
    typeof this;
}

vs

load(libdir + "asserts.js");

function BigInteger(a, b, c) { }

function montConvert(x) {
    var r = new BigInteger(null);
    return r;
}

var ba = new Array();

a = new BigInteger(ba);

g = montConvert(a);

var lfGlobal = newGlobal();

for (lfLocal in this) {
    if (!lfLocal in lfGlobal) {
        lfGlobal[lfLocal] = this[lfLocal];
    }
}

lfGlobal.offThreadCompileScript(`
  var dbg = new Debugger(g);
  dbg.onEnterFrame = function (frame) {
    var frameThis = frame.this;
  }
`);

lfGlobal.runOffThreadScript();

assertThrowsInstanceOf(test, ReferenceError);

function test() {
    function check(fun, msg, todo) {
        success = fun();
    }
    check(()  => Object.getPrototypeOf(view) == Object.getPrototypeOf(simple));
    typeof this;
}
// tests calling script functions via Debugger.Object.prototype.apply/call

load(libdir + "asserts.js");

var g = newGlobal();
g.eval("function f() { debugger; }");
var dbg = new Debugger(g);

var hits = 0;
function test(usingApply) {
    dbg.onDebuggerStatement = function (frame) {
        var fn = frame.arguments[0];
        var cv = usingApply ? fn.apply(null, [9, 16]) : fn.call(null, 9, 16);
        assertEq(Object.keys(cv).join(","), "return");
        assertEq(Object.getPrototypeOf(cv), Object.prototype);
        assertEq(cv.return, 25);

        cv = usingApply ? fn.apply(null, ["hello ", "world"]) : fn.call(null, "hello ", "world");
        assertEq(Object.keys(cv).join(","), "return");
        assertEq(cv.return, "hello world");

        // Handle more or less arguments.
        assertEq((usingApply ? fn.apply(null, [1, 5, 100]) : fn.call(null, 1, 5, 100)).return, 6);
        assertEq((usingApply ? fn.apply(null, []) : fn.call(null)).return, NaN);
        assertEq((usingApply ? fn.apply() : fn.call()).return, NaN);

        // Throw if a this-value or argument is an object but not a Debugger.Object.
        assertThrowsInstanceOf(function () { usingApply ? fn.apply({}, []) : fn.call({}); },
                               TypeError);
        assertThrowsInstanceOf(function () { usingApply ? fn.apply(null, [{}]) : fn.call(null, {}); },
                               TypeError);
        hits++;
    };
    g.eval("f(function (a, b) { return a + b; });");

    // The callee receives the right arguments even if more arguments are provided
    // than the callee's .length.
    dbg.onDebuggerStatement = function (frame) {
        assertEq((usingApply ? frame.arguments[0].apply(null, ['one', 'two'])
                             : frame.arguments[0].call(null, 'one', 'two')).return,
                 2);
        hits++;
    };
    g.eval("f(function () { return arguments.length; });");

    // Exceptions are reported as {throw:} completion values.
    dbg.onDebuggerStatement = function (frame) {
        var lose = frame.arguments[0];
        var cv = usingApply ? lose.apply(null, []) : lose.call(null);
        assertEq(Object.keys(cv).join(","), "throw");
        assertEq(cv.throw, frame.callee);
        hits++;
    };
    g.eval("f(function lose() { throw f; });");
}

test(true);
test(false);
assertEq(hits, 6);

vs

load(libdir + "asserts.js");

var g = newGlobal();

g.eval("function f() { debugger; }");

var dbg = new Debugger(g);

var hits = 0;

function test(usingApply) {
    dbg.onDebuggerStatement = function(frame) {
        var fn = frame.arguments[0];
        var cv = usingApply ? fn.apply(null, [9, 16,]) : fn.call(null, 9, 16);
        assertEq(Object.keys(cv).join(","), "return");
        assertEq(Object.getPrototypeOf(cv), Object.prototype);
        assertEq(cv.return, 25);
        cv = usingApply ? fn.apply(null, ["hello ", "world",]) : fn.call(null, "hello ", "world");
        assertEq(Object.keys(cv).join(","), "return");
        assertEq(cv.return, "hello world");
        assertEq(usingApply ? fn.apply(null, [1, 5, 100,]) : fn.call(null, 1, 5, 100).return, 6);
        assertEq(usingApply ? fn.apply(null, []) : fn.call(null).return, NaN);
        assertEq(usingApply ? fn.apply() : fn.call().return, NaN);
        assertThrowsInstanceOf(function() {
            usingApply ? fn.apply({            }, []) : fn.call({            });
        }, TypeError);
        assertThrowsInstanceOf(function() {
            usingApply ? fn.apply(null, [{            },]) : fn.call(null, {            });
        }, TypeError);
        hits++;
    };
    g.eval("f(function (a, b) { return a + b; });");
    dbg.onDebuggerStatement = function(frame) {
        assertEq(usingApply ? frame.arguments[0].apply(null, ['one', 'two',]) : frame.arguments[0].call(null, 'one', 'two').return, 2);
        hits++;
    };
    g.eval("f(function () { return arguments.length; });");
    dbg.onDebuggerStatement = function(frame) {
        var lose = frame.arguments[0];
        var cv = usingApply ? lose.apply(null, []) : lose.call(null);
        assertEq(Object.keys(cv).join(","), "throw");
        assertEq(cv.throw, frame.callee);
        hits++;
    };
    g.eval("f(function lose() { throw f; });");
}

test(true);

test(false);

assertEq(hits, 6);
// frame.live is false for generator frames popped due to exception or termination.

load(libdir + "/asserts.js");

function test(when, what) {
    let g = newGlobal();
    g.eval("function* f(x) { yield x; }");

    let dbg = new Debugger;
    let gw = dbg.addDebuggee(g);
    let fw = gw.getOwnPropertyDescriptor("f").value;

    let t = 0;
    let poppedFrame;

    function tick(frame) {
        if (frame.callee == fw) {
            if (t == when) {
                poppedFrame = frame;
                dbg.onEnterFrame = undefined;
                frame.onPop = undefined;
                return what;
            }
            t++;
        }
        return undefined;
    }

    dbg.onDebuggerStatement = frame => {
        dbg.onEnterFrame = frame => {
            frame.onPop = function() {
                return tick(this);
            };
            return tick(frame);
        };
        let result = frame.eval("for (let _ of f(0)) {}");
        assertDeepEq(result, what);
    };
    g.eval("debugger;");

    assertEq(t, when);
    assertEq(poppedFrame.live, false);
    assertErrorMessage(() => poppedFrame.older,
                       Error,
                       "Debugger.Frame is not live");
}

for (let when = 0; when < 6; when++) {
    for (let what of [null, {throw: "fit"}]) {
        test(when, what);
    }
}

vs

load(libdir + "/asserts.js");

function test(when, what) {
    let g = newGlobal();
    g.eval("function* f(x) { yield x; }");
    let dbg = new Debugger();
    let gw = dbg.addDebuggee(g);
    let fw = gw.getOwnPropertyDescriptor("f").value;
    let t = 0;
    let poppedFrame;
    function tick(frame) {
        if (frame.callee == fw) {
            if (t == when) {
                poppedFrame = frame;

                dbg.onEnterFrame = undefined;

                frame.onPop = undefined;

                return what;
            }

            t++;
        }
        return undefined;
    }
    dbg.onDebuggerStatement = frame => {
        dbg.onEnterFrame = frame => {
            frame.onPop = function() {
                return tick(this);
            };
            return tick(frame);
        };
        let result = frame.eval("for (let _ of f(0)) {}");
        assertDeepEq(result, what);
    };
    g.eval("debugger;");
    assertEq(t, when);
    assertEq(poppedFrame.live, false);
    assertErrorMessage(()  => poppedFrame.older, Error, "Debugger.Frame is not live");
}

for (let when = 0;when < 6;when++) {
    for (what of [null, {
        throw: "fit",
    },]) {
        test(when, what);
    }
}
// |jit-test| --ion-gvn=off;

try  {
    var g = newGlobal();
    var dbg = new Debugger(g);
    dbg.onExceptionUnwind = function(m) {
        do {
            m = m.older;
        } while (m != null);
    };
    g.eval("try { throw (function() {});} finally {}");
} catch(e) {

}

vs

try {
    var g = newGlobal();

    var dbg = new Debugger(g);

    dbg.onExceptionUnwind = (function(m) {
        do {
            m = m.older;
        } while (m != null);
        ;
    });

    g.eval("try { throw (function() {});} finally {}");
} catch (e) { 
    
}
setJitCompilerOption("baseline.warmup.trigger", 10);
setJitCompilerOption("ion.warmup.trigger", 20);

function myFloor(x) {
    if(x >= 0)
        return x - Math.abs(x % 1);
    else
        return x - Math.abs(1 + (x % 1));
}

function floorRangeTest(x) {
    if(10 < x) {
        if(x < 100) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if(-100 < x) {
        if(x < -10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if (-(4294967296 - 1) < x) {
        if(x < 10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if (-10 < x) {
        if(x < 4294967296) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if (-2147483648 < x) {
        if(x < 10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if ((-2147483648 -1) < x) {
        if(x < 10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if (10 < x) {
        if(x < 2147483648) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if (10 < x) {
        if(x < 2147483649) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }

    if (Math.pow(2,31) < x) {
        if(x < Math.pow(2,33)) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
}

var a = [Math.pow(2,31), Math.pow(2,33), -4294967296.4, 214748364.2, -50.4, 50.4];

for(var i = 0; i < 10; i++) {
  for (var j = 0; j < a.length; j++) {
      floorRangeTest(a[j]);
  }
}

for (var j = 0; j < 30; j++) {
    (function() {
        Math.floor(1.5);
    })()
}

for (var j = 0; j < 30; j++) {
    (function() {
        Math.floor(-1.5);
    })()
}

for (var j = 0; j < 30; j++) {
    (function() {
        Math.floor(-127.5);
    })()
}

vs

setJitCompilerOption("baseline.warmup.trigger", 10);

setJitCompilerOption("ion.warmup.trigger", 20);

function myFloor(x) {
    if (x >= 0) return x - Math.abs(x % 1);
 else return x - Math.abs(1 + x % 1);

}

function floorRangeTest(x) {
    if (10 < x) {
        if (x < 100) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (-100 < x) {
        if (x < -10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (-4294967296 - 1 < x) {
        if (x < 10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (-10 < x) {
        if (x < 4294967296) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (-2147483648 < x) {
        if (x < 10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (-2147483648 - 1 < x) {
        if (x < 10) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (10 < x) {
        if (x < 2147483648) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (10 < x) {
        if (x < 2147483649) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
    if (Math.pow(2, 31) < x) {
        if (x < Math.pow(2, 33)) {
            assertEq(Math.floor(x), myFloor(x));
        }
    }
}

var a = [Math.pow(2, 31), Math.pow(2, 33), -4294967296.4, 214748364.2, -50.4, 50.4,];

for (let i = 0;i < 10;i++) {
    for (let j = 0;j < a.length;j++) {
        floorRangeTest(a[j]);
    }
}

for (let j = 0;j < 30;j++) {
    function() {
        Math.floor(1.5);
    }();
}

for (let j = 0;j < 30;j++) {
    function() {
        Math.floor(-1.5);
    }();
}

for (let j = 0;j < 30;j++) {
    function() {
        Math.floor(-127.5);
    }();
}
// Run debugger in its own global
let g = newGlobal();
g.target = this;
g.evaluate(`
    let d = new Debugger;
    let gw = d.addDebuggee(target);

    d.onDebuggerStatement = function(frame)
    {
        frame = frame.older;

        let res = frame.eval("this");
        assertEq(res.return, frame.this);

        res = frame.evalWithBindings("this", {x:42});
        assertEq(res.return, frame.this);
    }
`);

// Debugger statement affects parse so hide in another function
function brk() { debugger; }

function f1() {
    var temp = "string";
    brk();
}

function f2() {
    let temp = "string";
    brk();
}

function f3() {
    const temp = "string";
    brk();
}

f1.call({});
f2.call({});
f3.call({});

vs

let g = newGlobal();

g.target = this;

g.evaluate(`
    let d = new Debugger;
    let gw = d.addDebuggee(target);

    d.onDebuggerStatement = function(frame)
    {
        frame = frame.older;

        let res = frame.eval("this");
        assertEq(res.return, frame.this);

        res = frame.evalWithBindings("this", {x:42});
        assertEq(res.return, frame.this);
    }
`);

function brk() {
    debugger;;
}

function f1() {
    var temp = "string";
    brk();
}

function f2() {
    let temp = "string";
    brk();
}

function f3() {
    const temp = "string";
    brk();
}

f1.call(({}));

f2.call(({}));

f3.call(({}));
// |jit-test| skip-if: !wasmBulkMemSupported()

const Module = WebAssembly.Module;
const Instance = WebAssembly.Instance;

// Some non-boundary tests for {table,memory}.{init,drop,copy}.  The table
// case is more complex and appears first.  The memory case is a simplified
// version of it.

// This module exports 5 functions ..
let tab_expmod_t =
    `(module
        (func (export "ef0") (result i32) (i32.const 0))
        (func (export "ef1") (result i32) (i32.const 1))
        (func (export "ef2") (result i32) (i32.const 2))
        (func (export "ef3") (result i32) (i32.const 3))
        (func (export "ef4") (result i32) (i32.const 4))
     )`;

// .. and this one imports those 5 functions.  It adds 5 of its own, creates a
// 30 element table using both active and passive initialisers, with a mixture
// of the imported and local functions.  |testfn| is exported.  It uses the
// supplied |insn| to modify the table somehow, and then will indirect-call
// the table entry number specified as a parameter.  That will either return a
// value 0 to 9 indicating the function called, or will throw an exception if
// the table entry is empty.
function gen_tab_impmod_t(insn)
{
  let t =
  `(module
     ;; -------- Types --------
     (type (func (result i32)))  ;; type #0
     ;; -------- Tables --------
     (table 30 30 anyfunc)
     ;; -------- Table initialisers --------
     (elem (i32.const 2) 3 1 4 1)
     (elem passive 2 7 1 8)
     (elem (i32.const 12) 7 5 2 3 6)
     (elem passive 5 9 2 7 6)
     ;; -------- Imports --------
     (import "a" "if0" (result i32))    ;; index 0
     (import "a" "if1" (result i32))
     (import "a" "if2" (result i32))
     (import "a" "if3" (result i32))
     (import "a" "if4" (result i32))    ;; index 4
     ;; -------- Functions --------
     (func (result i32) (i32.const 5))  ;; index 5
     (func (result i32) (i32.const 6))
     (func (result i32) (i32.const 7))
     (func (result i32) (i32.const 8))
     (func (result i32) (i32.const 9))  ;; index 9

     (func (export "testfn") (param i32) (result i32)
       ${insn}
       ;; call the selected table entry, which will either return a value,
       ;; or will cause an exception.
       get_local 0      ;; callIx
       call_indirect 0  ;; and its return value is our return value.
     )
   )`;
   return t;
};

// This is the test driver.  It constructs the abovementioned module, using
// the given |instruction| to modify the table, and then probes the table
// by making indirect calls, one for each element of |expected_result_vector|.
// The results are compared to those in the vector.

function tab_test(instruction, expected_result_vector)
{
    let tab_expmod_b = wasmTextToBinary(tab_expmod_t);
    let tab_expmod_i = new Instance(new Module(tab_expmod_b));

    let tab_impmod_t = gen_tab_impmod_t(instruction);
    let tab_impmod_b = wasmTextToBinary(tab_impmod_t);

    for (let i = 0; i < expected_result_vector.length; i++) {
        let inst = new Instance(new Module(tab_impmod_b),
                                {a:{if0:tab_expmod_i.exports.ef0,
                                    if1:tab_expmod_i.exports.ef1,
                                    if2:tab_expmod_i.exports.ef2,
                                    if3:tab_expmod_i.exports.ef3,
                                    if4:tab_expmod_i.exports.ef4
                                   }});
        let expected = expected_result_vector[i];
        let actual = undefined;
        try {
            actual = inst.exports.testfn(i);
            assertEq(actual !== null, true);
        } catch (e) {
            if (!(e instanceof Error &&
                  e.message.match(/indirect call to null/)))
                throw e;
            // actual remains undefined
        }
        assertEq(actual, expected,
                 "tab_test fail: insn = '" + instruction + "', index = " +
                 i + ", expected = " + expected + ", actual = " + actual);
    }
}

// Using 'e' for empty (undefined) spaces in the table, to make it easier
// to count through the vector entries when debugging.
let e = undefined;

// This just gives the initial state of the table, with its active
// initialisers applied
tab_test("nop",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-null over non-null
tab_test("(table.copy (i32.const 13) (i32.const 2) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-null over null
tab_test("(table.copy (i32.const 25) (i32.const 15) (i32.const 2))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]);

// Copy null over non-null
tab_test("(table.copy (i32.const 13) (i32.const 25) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null over null
tab_test("(table.copy (i32.const 20) (i32.const 22) (i32.const 4))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, non overlapping
tab_test("(table.copy (i32.const 25) (i32.const 1) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]);

// Copy null and non-null entries, overlapping, backwards
tab_test("(table.copy (i32.const 10) (i32.const 12) (i32.const 7))",
         [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy null and non-null entries, overlapping, forwards
tab_test("(table.copy (i32.const 12) (i32.const 10) (i32.const 7))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]);

// Passive init that overwrites all-null entries
tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))",
         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Passive init that overwrites existing active-init-created entries
tab_test("(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);

// Perform active and passive initialisation and then multiple copies
tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" +
         "table.drop 1 \n" +
         "(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" +
         "table.drop 3 \n" +
         "(table.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" +
         "(table.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" +
         "(table.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" +
         "(table.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" +
         "(table.copy (i32.const 19) (i32.const 20) (i32.const 5))",
         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);


// And now a simplified version of the above, for memory.{init,drop,copy}.

function gen_mem_mod_t(insn)
{
  let t =
  `(module
     ;; -------- Memories --------
     (memory (export "memory0") 1 1)
     ;; -------- Memory initialisers --------
     (data (i32.const 2) "\\03\\01\\04\\01")
     (data passive "\\02\\07\\01\\08")
     (data (i32.const 12) "\\07\\05\\02\\03\\06")
     (data passive "\\05\\09\\02\\07\\06")

     (func (export "testfn")
       ${insn}
       ;; There's no return value.  The JS driver can just pull out the
       ;; final memory and examine it.
     )
   )`;
   return t;
};

function mem_test(instruction, expected_result_vector)
{
    let mem_mod_t = gen_mem_mod_t(instruction);
    let mem_mod_b = wasmTextToBinary(mem_mod_t);

    let inst = new Instance(new Module(mem_mod_b));
    inst.exports.testfn();
    let buf = new Uint8Array(inst.exports.memory0.buffer);

    for (let i = 0; i < expected_result_vector.length; i++) {
        let expected = expected_result_vector[i];
        let actual = buf[i];
        assertEq(actual, expected,
                 "mem_test fail: insn = '" + instruction + "', index = " +
                 i + ", expected = " + expected + ", actual = " + actual);
    }
}

e = 0;

// This just gives the initial state of the memory, with its active
// initialisers applied.
mem_test("nop",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-zero over non-zero
mem_test("(memory.copy (i32.const 13) (i32.const 2) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy non-zero over zero
mem_test("(memory.copy (i32.const 25) (i32.const 15) (i32.const 2))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]);

// Copy zero over non-zero
mem_test("(memory.copy (i32.const 13) (i32.const 25) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy zero over zero
mem_test("(memory.copy (i32.const 20) (i32.const 22) (i32.const 4))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy zero and non-zero entries, non overlapping
mem_test("(memory.copy (i32.const 25) (i32.const 1) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]);

// Copy zero and non-zero entries, overlapping, backwards
mem_test("(memory.copy (i32.const 10) (i32.const 12) (i32.const 7))",
         [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Copy zero and non-zero entries, overlapping, forwards
mem_test("(memory.copy (i32.const 12) (i32.const 10) (i32.const 7))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]);

// Passive init that overwrites all-zero entries
mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))",
         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);

// Passive init that overwrites existing active-init-created entries
mem_test("(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))",
         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);

// Perform active and passive initialisation and then multiple copies
mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" +
         "memory.drop 1 \n" +
         "(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" +
         "memory.drop 3 \n" +
         "(memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" +
         "(memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" +
         "(memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" +
         "(memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" +
         "(memory.copy (i32.const 19) (i32.const 20) (i32.const 5))",
         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);


//---------------------------------------------------------------------//
//---------------------------------------------------------------------//
// Some further tests for memory.copy and memory.fill.  First, validation
// tests.

//-----------------------------------------------------------
// Test helpers.  Copied and simplified from binary.js.

load(libdir + "wasm-binary.js");

function toU8(array) {
    for (let b of array)
        assertEq(b < 256, true);
    return Uint8Array.from(array);
}

function varU32(u32) {
    assertEq(u32 >= 0, true);
    assertEq(u32 < Math.pow(2,32), true);
    var bytes = [];
    do {
        var byte = u32 & 0x7f;
        u32 >>>= 7;
        if (u32 != 0)
            byte |= 0x80;
        bytes.push(byte);
    } while (u32 != 0);
    return bytes;
}

function moduleHeaderThen(...rest) {
    return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest];
}

function moduleWithSections(sectionArray) {
    var bytes = moduleHeaderThen();
    for (let section of sectionArray) {
        bytes.push(section.name);
        bytes.push(...varU32(section.body.length));
        bytes.push(...section.body);
    }
    return toU8(bytes);
}

function sigSection(sigs) {
    var body = [];
    body.push(...varU32(sigs.length));
    for (let sig of sigs) {
        body.push(...varU32(FuncCode));
        body.push(...varU32(sig.args.length));
        for (let arg of sig.args)
            body.push(...varU32(arg));
        body.push(...varU32(sig.ret == VoidCode ? 0 : 1));
        if (sig.ret != VoidCode)
            body.push(...varU32(sig.ret));
    }
    return { name: typeId, body };
}

function declSection(decls) {
    var body = [];
    body.push(...varU32(decls.length));
    for (let decl of decls)
        body.push(...varU32(decl));
    return { name: functionId, body };
}

function funcBody(func) {
    var body = varU32(func.locals.length);
    for (let local of func.locals)
        body.push(...varU32(local));
    body = body.concat(...func.body);
    body.push(EndCode);
    body.splice(0, 0, ...varU32(body.length));
    return body;
}

function bodySection(bodies) {
    var body = varU32(bodies.length).concat(...bodies);
    return { name: codeId, body };
}

function memorySection(initialSize) {
    var body = [];
    body.push(...varU32(1));           // number of memories
    body.push(...varU32(0x0));         // for now, no maximum
    body.push(...varU32(initialSize));
    return { name: memoryId, body };
}

const v2vSig = {args:[], ret:VoidCode};
const v2vSigSection = sigSection([v2vSig]);

// Prefixed opcodes

function checkMiscPrefixed(opcode, expect_failure) {
    let binary = moduleWithSections(
           [v2vSigSection, declSection([0]), memorySection(1),
            bodySection(
                [funcBody(
                    {locals:[],
                     body:[0x41, 0x0, 0x41, 0x0, 0x41, 0x0, // 3 x const.i32 0
                           MiscPrefix, ...opcode]})])]);
    if (expect_failure) {
        assertErrorMessage(() => new WebAssembly.Module(binary),
                           WebAssembly.CompileError, /unrecognized opcode/);
    } else {
        assertEq(WebAssembly.validate(binary), true);
    }
}

//-----------------------------------------------------------
// Verification cases for memory.copy/fill opcode encodings

checkMiscPrefixed([0x0a, 0x00], false); // memory.copy, flags=0
checkMiscPrefixed([0x0b, 0x00], false); // memory.fill, flags=0
checkMiscPrefixed([0x0b, 0x80, 0x00], false); // memory.fill, flags=0 (long encoding)
checkMiscPrefixed([0x13], true);        // table.size+1, which is currently unassigned

//-----------------------------------------------------------
// Verification cases for memory.copy/fill arguments

// Invalid argument types
{
    const tys = ['i32', 'f32', 'i64', 'f64'];
    const ops = ['copy', 'fill'];
    for (let ty1 of tys) {
    for (let ty2 of tys) {
    for (let ty3 of tys) {
    for (let op of ops) {
        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
            continue;  // this is the only valid case
        let text =
        `(module
          (memory (export "memory") 1 1)
           (func (export "testfn")
           (memory.${op} (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30))
          )
         )`;
        assertErrorMessage(() => wasmEvalText(text),
                           WebAssembly.CompileError, /type mismatch/);
    }}}}
}

// Not enough, or too many, args
{
    for (let op of ['copy', 'fill']) {
        let text1 =
        `(module
          (memory (export "memory") 1 1)
          (func (export "testfn")
           (i32.const 10)
           (i32.const 20)
           memory.${op}
         )
        )`;
        assertErrorMessage(() => wasmEvalText(text1),
                           WebAssembly.CompileError,
                           /popping value from empty stack/);
        let text2 =
        `(module
          (memory (export "memory") 1 1)
          (func (export "testfn")
           (i32.const 10)
           (i32.const 20)
           (i32.const 30)
           (i32.const 40)
           memory.${op}
         )
        )`;
        assertErrorMessage(() => wasmEvalText(text2),
                           WebAssembly.CompileError,
                           /unused values not explicitly dropped by end of block/);
    }
}

// Module doesn't have a memory
{
    for (let op of ['copy', 'fill']) {
        let text =
        `(module
          (func (export "testfn")
           (memory.${op} (i32.const 10) (i32.const 20) (i32.const 30))
         )
        )`;
        assertErrorMessage(() => wasmEvalText(text),
                           WebAssembly.CompileError,
                           /can't touch memory without memory/);
    }
}

//---------------------------------------------------------------------//
//---------------------------------------------------------------------//
// Run tests

//-----------------------------------------------------------
// Test helpers
function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
{
    for (let i = minIx; i < maxIxPlusOne; i++) {
        assertEq(arr[i], expectedValue);
    }
}

//-----------------------------------------------------------
// Test cases for memory.fill

// Range valid
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0x00000, 0x0FF00, 0x00);
    checkRange(b, 0x0FF00, 0x10000, 0x55);
}

// Range invalid
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Wraparound the end of 32-bit offset space
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Zero len with offset in-bounds is a no-op
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0x00000, 0x10000, 0x00);
}

// Zero len with offset out-of-bounds gets an exception
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Very large range
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0x00000, 0x00001, 0x00);
    checkRange(b, 0x00001, 0x0FFFF, 0xAA);
    checkRange(b, 0x0FFFF, 0x10000, 0x00);
}

// Sequencing
{
    let i = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn") (result i32)
         (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10))
         (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4))
         i32.const 99
       )
     )`
    );
    i.exports.testfn();
    let b = new Uint8Array(i.exports.memory.buffer);
    checkRange(b, 0x0,     0x12+0,  0x00);
    checkRange(b, 0x12+0,  0x12+3,  0x55);
    checkRange(b, 0x12+3,  0x12+7,  0xAA);
    checkRange(b, 0x12+7,  0x12+10, 0x55);
    checkRange(b, 0x12+10, 0x10000, 0x00);
}


//-----------------------------------------------------------
// Test cases for memory.copy

// Both ranges valid.  Copy 5 bytes backwards by 1 (overlapping).
// result = 0x00--(09) 0x55--(11) 0x00--(pagesize-20)
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
         (memory.copy (i32.const 9) (i32.const 10) (i32.const 5))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0,    0+9,     0x00);
    checkRange(b, 9,    9+11,    0x55);
    checkRange(b, 9+11, 0x10000, 0x00);
}

// Both ranges valid.  Copy 5 bytes forwards by 1 (overlapping).
// result = 0x00--(10) 0x55--(11) 0x00--(pagesize-19)
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
         (memory.copy (i32.const 16) (i32.const 15) (i32.const 5))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0,     0+10,    0x00);
    checkRange(b, 10,    10+11,   0x55);
    checkRange(b, 10+11, 0x10000, 0x00);
}

// Destination range invalid
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Destination wraparound the end of 32-bit offset space
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Source range invalid
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Source wraparound the end of 32-bit offset space
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Zero len with both offsets in-bounds is a no-op
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000))
         (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000))
         (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0x00000, 0x08000, 0x55);
    checkRange(b, 0x08000, 0x10000, 0xAA);
}

// Zero len with dest offset out-of-bounds is an exception
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// Zero len with src offset out-of-bounds is an exception
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))
       )
     )`
    );
    assertErrorMessage(() => inst.exports.testfn(),
                       WebAssembly.RuntimeError, /index out of bounds/);
}

// 100 random fills followed by 100 random copies, in a single-page buffer,
// followed by verification of the (now heavily mashed-around) buffer.
{
    let inst = wasmEvalText(
    `(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
         (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
         (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
         (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
         (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
         (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
         (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
         (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
         (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
         (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
         (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
         (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
         (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
         (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
         (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
         (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
         (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
         (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
         (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
         (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
         (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
         (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
         (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
         (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
         (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
         (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
         (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
         (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
         (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
         (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
         (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
         (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
         (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
         (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
         (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
         (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
         (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
         (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
         (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
         (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
         (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
         (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
         (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
         (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
         (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
         (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
         (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
         (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
         (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
         (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
         (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
         (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
         (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
         (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
         (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
         (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
         (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
         (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
         (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
         (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
         (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
         (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
         (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
         (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
         (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
         (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
         (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
         (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
         (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
         (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
         (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
         (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
         (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
         (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
         (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
         (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
         (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
         (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
         (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
         (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
         (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
         (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
         (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
         (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
         (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
         (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
         (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
         (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
         (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
         (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
         (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
         (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
         (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
         (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
         (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
         (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
         (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
         (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
         (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
         (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
         (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
         (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
         (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
         (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
         (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
         (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
         (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
         (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
         (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
         (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
         (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
         (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
         (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
         (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
         (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
         (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
         (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
         (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
         (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
         (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
         (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
         (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
         (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
         (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
         (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
         (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
         (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
         (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
         (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
         (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
         (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
         (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
         (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
         (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
         (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
         (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
         (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
         (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
         (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
         (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
         (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
         (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
         (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
         (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
         (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
         (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
         (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
         (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
         (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
         (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
         (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
         (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
         (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
         (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
         (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
         (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
         (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
         (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
         (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
         (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
         (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
         (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
         (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
         (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
         (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
         (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
         (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
         (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
         (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
         (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
         (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
         (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
         (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
         (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
         (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
         (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
         (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
         (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
         (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
         (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
         (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
         (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
         (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
         (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
         (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
         (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
         (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
         (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
         (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
         (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
         (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
         (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
         (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
         (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
         (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
         (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
         (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
         (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
         (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
         (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
       )
     )`
    );
    inst.exports.testfn();
    let b = new Uint8Array(inst.exports.memory.buffer);
    checkRange(b, 0, 124, 0);
    checkRange(b, 124, 1517, 9);
    checkRange(b, 1517, 2132, 0);
    checkRange(b, 2132, 2827, 10);
    checkRange(b, 2827, 2921, 92);
    checkRange(b, 2921, 3538, 83);
    checkRange(b, 3538, 3786, 77);
    checkRange(b, 3786, 4042, 97);
    checkRange(b, 4042, 4651, 99);
    checkRange(b, 4651, 5057, 0);
    checkRange(b, 5057, 5109, 99);
    checkRange(b, 5109, 5291, 0);
    checkRange(b, 5291, 5524, 72);
    checkRange(b, 5524, 5691, 92);
    checkRange(b, 5691, 6552, 83);
    checkRange(b, 6552, 7133, 77);
    checkRange(b, 7133, 7665, 99);
    checkRange(b, 7665, 8314, 0);
    checkRange(b, 8314, 8360, 62);
    checkRange(b, 8360, 8793, 86);
    checkRange(b, 8793, 8979, 83);
    checkRange(b, 8979, 9373, 79);
    checkRange(b, 9373, 9518, 95);
    checkRange(b, 9518, 9934, 59);
    checkRange(b, 9934, 10087, 77);
    checkRange(b, 10087, 10206, 5);
    checkRange(b, 10206, 10230, 77);
    checkRange(b, 10230, 10249, 41);
    checkRange(b, 10249, 11148, 83);
    checkRange(b, 11148, 11356, 74);
    checkRange(b, 11356, 11380, 93);
    checkRange(b, 11380, 11939, 74);
    checkRange(b, 11939, 12159, 68);
    checkRange(b, 12159, 12575, 83);
    checkRange(b, 12575, 12969, 79);
    checkRange(b, 12969, 13114, 95);
    checkRange(b, 13114, 14133, 59);
    checkRange(b, 14133, 14404, 76);
    checkRange(b, 14404, 14428, 57);
    checkRange(b, 14428, 14458, 59);
    checkRange(b, 14458, 14580, 32);
    checkRange(b, 14580, 14777, 89);
    checkRange(b, 14777, 15124, 59);
    checkRange(b, 15124, 15126, 36);
    checkRange(b, 15126, 15192, 100);
    checkRange(b, 15192, 15871, 96);
    checkRange(b, 15871, 15998, 95);
    checkRange(b, 15998, 17017, 59);
    checkRange(b, 17017, 17288, 76);
    checkRange(b, 17288, 17312, 57);
    checkRange(b, 17312, 17342, 59);
    checkRange(b, 17342, 17464, 32);
    checkRange(b, 17464, 17661, 89);
    checkRange(b, 17661, 17727, 59);
    checkRange(b, 17727, 17733, 5);
    checkRange(b, 17733, 17893, 96);
    checkRange(b, 17893, 18553, 77);
    checkRange(b, 18553, 18744, 42);
    checkRange(b, 18744, 18801, 76);
    checkRange(b, 18801, 18825, 57);
    checkRange(b, 18825, 18876, 59);
    checkRange(b, 18876, 18885, 77);
    checkRange(b, 18885, 18904, 41);
    checkRange(b, 18904, 19567, 83);
    checkRange(b, 19567, 20403, 96);
    checkRange(b, 20403, 21274, 77);
    checkRange(b, 21274, 21364, 100);
    checkRange(b, 21364, 21468, 74);
    checkRange(b, 21468, 21492, 93);
    checkRange(b, 21492, 22051, 74);
    checkRange(b, 22051, 22480, 68);
    checkRange(b, 22480, 22685, 100);
    checkRange(b, 22685, 22694, 68);
    checkRange(b, 22694, 22821, 10);
    checkRange(b, 22821, 22869, 100);
    checkRange(b, 22869, 24107, 97);
    checkRange(b, 24107, 24111, 37);
    checkRange(b, 24111, 24236, 77);
    checkRange(b, 24236, 24348, 72);
    checkRange(b, 24348, 24515, 92);
    checkRange(b, 24515, 24900, 83);
    checkRange(b, 24900, 25136, 95);
    checkRange(b, 25136, 25182, 85);
    checkRange(b, 25182, 25426, 68);
    checkRange(b, 25426, 25613, 89);
    checkRange(b, 25613, 25830, 96);
    checkRange(b, 25830, 26446, 100);
    checkRange(b, 26446, 26517, 10);
    checkRange(b, 26517, 27468, 92);
    checkRange(b, 27468, 27503, 95);
    checkRange(b, 27503, 27573, 77);
    checkRange(b, 27573, 28245, 92);
    checkRange(b, 28245, 28280, 95);
    checkRange(b, 28280, 29502, 77);
    checkRange(b, 29502, 29629, 42);
    checkRange(b, 29629, 30387, 83);
    checkRange(b, 30387, 30646, 77);
    checkRange(b, 30646, 31066, 92);
    checkRange(b, 31066, 31131, 77);
    checkRange(b, 31131, 31322, 42);
    checkRange(b, 31322, 31379, 76);
    checkRange(b, 31379, 31403, 57);
    checkRange(b, 31403, 31454, 59);
    checkRange(b, 31454, 31463, 77);
    checkRange(b, 31463, 31482, 41);
    checkRange(b, 31482, 31649, 83);
    checkRange(b, 31649, 31978, 72);
    checkRange(b, 31978, 32145, 92);
    checkRange(b, 32145, 32530, 83);
    checkRange(b, 32530, 32766, 95);
    checkRange(b, 32766, 32812, 85);
    checkRange(b, 32812, 33056, 68);
    checkRange(b, 33056, 33660, 89);
    checkRange(b, 33660, 33752, 59);
    checkRange(b, 33752, 33775, 36);
    checkRange(b, 33775, 33778, 32);
    checkRange(b, 33778, 34603, 9);
    checkRange(b, 34603, 35218, 0);
    checkRange(b, 35218, 35372, 10);
    checkRange(b, 35372, 35486, 77);
    checkRange(b, 35486, 35605, 5);
    checkRange(b, 35605, 35629, 77);
    checkRange(b, 35629, 35648, 41);
    checkRange(b, 35648, 36547, 83);
    checkRange(b, 36547, 36755, 74);
    checkRange(b, 36755, 36767, 93);
    checkRange(b, 36767, 36810, 83);
    checkRange(b, 36810, 36839, 100);
    checkRange(b, 36839, 37444, 96);
    checkRange(b, 37444, 38060, 100);
    checkRange(b, 38060, 38131, 10);
    checkRange(b, 38131, 39082, 92);
    checkRange(b, 39082, 39117, 95);
    checkRange(b, 39117, 39187, 77);
    checkRange(b, 39187, 39859, 92);
    checkRange(b, 39859, 39894, 95);
    checkRange(b, 39894, 40257, 77);
    checkRange(b, 40257, 40344, 89);
    checkRange(b, 40344, 40371, 59);
    checkRange(b, 40371, 40804, 77);
    checkRange(b, 40804, 40909, 5);
    checkRange(b, 40909, 42259, 92);
    checkRange(b, 42259, 42511, 77);
    checkRange(b, 42511, 42945, 83);
    checkRange(b, 42945, 43115, 77);
    checkRange(b, 43115, 43306, 42);
    checkRange(b, 43306, 43363, 76);
    checkRange(b, 43363, 43387, 57);
    checkRange(b, 43387, 43438, 59);
    checkRange(b, 43438, 43447, 77);
    checkRange(b, 43447, 43466, 41);
    checkRange(b, 43466, 44129, 83);
    checkRange(b, 44129, 44958, 96);
    checkRange(b, 44958, 45570, 77);
    checkRange(b, 45570, 45575, 92);
    checkRange(b, 45575, 45640, 77);
    checkRange(b, 45640, 45742, 42);
    checkRange(b, 45742, 45832, 72);
    checkRange(b, 45832, 45999, 92);
    checkRange(b, 45999, 46384, 83);
    checkRange(b, 46384, 46596, 95);
    checkRange(b, 46596, 46654, 92);
    checkRange(b, 46654, 47515, 83);
    checkRange(b, 47515, 47620, 77);
    checkRange(b, 47620, 47817, 79);
    checkRange(b, 47817, 47951, 95);
    checkRange(b, 47951, 48632, 100);
    checkRange(b, 48632, 48699, 97);
    checkRange(b, 48699, 48703, 37);
    checkRange(b, 48703, 49764, 77);
    checkRange(b, 49764, 49955, 42);
    checkRange(b, 49955, 50012, 76);
    checkRange(b, 50012, 50036, 57);
    checkRange(b, 50036, 50087, 59);
    checkRange(b, 50087, 50096, 77);
    checkRange(b, 50096, 50115, 41);
    checkRange(b, 50115, 50370, 83);
    checkRange(b, 50370, 51358, 92);
    checkRange(b, 51358, 51610, 77);
    checkRange(b, 51610, 51776, 83);
    checkRange(b, 51776, 51833, 89);
    checkRange(b, 51833, 52895, 100);
    checkRange(b, 52895, 53029, 97);
    checkRange(b, 53029, 53244, 68);
    checkRange(b, 53244, 54066, 100);
    checkRange(b, 54066, 54133, 97);
    checkRange(b, 54133, 54137, 37);
    checkRange(b, 54137, 55198, 77);
    checkRange(b, 55198, 55389, 42);
    checkRange(b, 55389, 55446, 76);
    checkRange(b, 55446, 55470, 57);
    checkRange(b, 55470, 55521, 59);
    checkRange(b, 55521, 55530, 77);
    checkRange(b, 55530, 55549, 41);
    checkRange(b, 55549, 56212, 83);
    checkRange(b, 56212, 57048, 96);
    checkRange(b, 57048, 58183, 77);
    checkRange(b, 58183, 58202, 41);
    checkRange(b, 58202, 58516, 83);
    checkRange(b, 58516, 58835, 95);
    checkRange(b, 58835, 58855, 77);
    checkRange(b, 58855, 59089, 95);
    checkRange(b, 59089, 59145, 77);
    checkRange(b, 59145, 59677, 99);
    checkRange(b, 59677, 60134, 0);
    checkRange(b, 60134, 60502, 89);
    checkRange(b, 60502, 60594, 59);
    checkRange(b, 60594, 60617, 36);
    checkRange(b, 60617, 60618, 32);
    checkRange(b, 60618, 60777, 42);
    checkRange(b, 60777, 60834, 76);
    checkRange(b, 60834, 60858, 57);
    checkRange(b, 60858, 60909, 59);
    checkRange(b, 60909, 60918, 77);
    checkRange(b, 60918, 60937, 41);
    checkRange(b, 60937, 61600, 83);
    checkRange(b, 61600, 62436, 96);
    checkRange(b, 62436, 63307, 77);
    checkRange(b, 63307, 63397, 100);
    checkRange(b, 63397, 63501, 74);
    checkRange(b, 63501, 63525, 93);
    checkRange(b, 63525, 63605, 74);
    checkRange(b, 63605, 63704, 100);
    checkRange(b, 63704, 63771, 97);
    checkRange(b, 63771, 63775, 37);
    checkRange(b, 63775, 64311, 77);
    checkRange(b, 64311, 64331, 26);
    checkRange(b, 64331, 64518, 92);
    checkRange(b, 64518, 64827, 11);
    checkRange(b, 64827, 64834, 26);
    checkRange(b, 64834, 65536, 0);
}

vs

const Module = WebAssembly.Module;

const Instance = WebAssembly.Instance;

let tab_expmod_t = `(module
        (func (export "ef0") (result i32) (i32.const 0))
        (func (export "ef1") (result i32) (i32.const 1))
        (func (export "ef2") (result i32) (i32.const 2))
        (func (export "ef3") (result i32) (i32.const 3))
        (func (export "ef4") (result i32) (i32.const 4))
     )`;

function gen_tab_impmod_t(insn) {
    let t = `(module
     ;; -------- Types --------
     (type (func (result i32)))  ;; type #0
     ;; -------- Tables --------
     (table 30 30 anyfunc)
     ;; -------- Table initialisers --------
     (elem (i32.const 2) 3 1 4 1)
     (elem passive 2 7 1 8)
     (elem (i32.const 12) 7 5 2 3 6)
     (elem passive 5 9 2 7 6)
     ;; -------- Imports --------
     (import "a" "if0" (result i32))    ;; index 0
     (import "a" "if1" (result i32))
     (import "a" "if2" (result i32))
     (import "a" "if3" (result i32))
     (import "a" "if4" (result i32))    ;; index 4
     ;; -------- Functions --------
     (func (result i32) (i32.const 5))  ;; index 5
     (func (result i32) (i32.const 6))
     (func (result i32) (i32.const 7))
     (func (result i32) (i32.const 8))
     (func (result i32) (i32.const 9))  ;; index 9

     (func (export "testfn") (param i32) (result i32)
       ${insn}
       ;; call the selected table entry, which will either return a value,
       ;; or will cause an exception.
       get_local 0      ;; callIx
       call_indirect 0  ;; and its return value is our return value.
     )
   )`;
    return t;
}

;

function tab_test(instruction, expected_result_vector) {
    let tab_expmod_b = wasmTextToBinary(tab_expmod_t);
    let tab_expmod_i = new Instance(new Module(tab_expmod_b));
    let tab_impmod_t = gen_tab_impmod_t(instruction);
    let tab_impmod_b = wasmTextToBinary(tab_impmod_t);
    for (let i = 0;i < expected_result_vector.length;i++) {
        let inst = new Instance(new Module(tab_impmod_b), {
            a: {
                if0: tab_expmod_i.exports.ef0,
                if1: tab_expmod_i.exports.ef1,
                if2: tab_expmod_i.exports.ef2,
                if3: tab_expmod_i.exports.ef3,
                if4: tab_expmod_i.exports.ef4,
            },
        });

        let expected = expected_result_vector[i];

        let actual = undefined;

        try {
            actual = inst.exports.testfn(i);

            assertEq(actual !== null, true);
        } catch (e) {
            if (!e instanceof Error && e.message.match(/indirect call to null/)) throw e;

        }

        assertEq(actual, expected, "tab_test fail: insn = '" + instruction + "', index = " + i + ", expected = " + expected + ", actual = " + actual);
    }
}

let e = undefined;

tab_test("nop", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.copy (i32.const 13) (i32.const 2) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 3, 1, 4, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.copy (i32.const 25) (i32.const 15) (i32.const 2))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, 3, 6, e, e, e,]);

tab_test("(table.copy (i32.const 13) (i32.const 25) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, e, e, e, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.copy (i32.const 20) (i32.const 22) (i32.const 4))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.copy (i32.const 25) (i32.const 1) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, 3, 1, e, e,]);

tab_test("(table.copy (i32.const 10) (i32.const 12) (i32.const 7))", [e, e, 3, 1, 4, 1, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.copy (i32.const 12) (i32.const 10) (i32.const 7))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))", [e, e, 3, 1, 4, 1, e, 2, 7, 1, 8, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 9, 2, 7, e, e, e, e, e, e, e, e, e, e, e, e,]);

tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" + "table.drop 1 \n" + "(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" + "table.drop 3 \n" + "(table.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" + "(table.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" + "(table.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" + "(table.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" + "(table.copy (i32.const 19) (i32.const 20) (i32.const 5))", [e, e, 3, 1, 4, 1, e, 2, 7, 1, 8, e, 7, e, 7, 5, 2, 7, e, 9, e, 7, e, 8, 8, e, e, e, e, e,]);

function gen_mem_mod_t(insn) {
    let t = `(module
     ;; -------- Memories --------
     (memory (export "memory0") 1 1)
     ;; -------- Memory initialisers --------
     (data (i32.const 2) "\\03\\01\\04\\01")
     (data passive "\\02\\07\\01\\08")
     (data (i32.const 12) "\\07\\05\\02\\03\\06")
     (data passive "\\05\\09\\02\\07\\06")

     (func (export "testfn")
       ${insn}
       ;; There's no return value.  The JS driver can just pull out the
       ;; final memory and examine it.
     )
   )`;
    return t;
}

;

function mem_test(instruction, expected_result_vector) {
    let mem_mod_t = gen_mem_mod_t(instruction);
    let mem_mod_b = wasmTextToBinary(mem_mod_t);
    let inst = new Instance(new Module(mem_mod_b));
    inst.exports.testfn();
    let buf = new Uint8Array(inst.exports.memory0.buffer);
    for (let i = 0;i < expected_result_vector.length;i++) {
        let expected = expected_result_vector[i];

        let actual = buf[i];

        assertEq(actual, expected, "mem_test fail: insn = '" + instruction + "', index = " + i + ", expected = " + expected + ", actual = " + actual);
    }
}

e = 0;

mem_test("nop", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.copy (i32.const 13) (i32.const 2) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 3, 1, 4, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.copy (i32.const 25) (i32.const 15) (i32.const 2))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, 3, 6, e, e, e,]);

mem_test("(memory.copy (i32.const 13) (i32.const 25) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, e, e, e, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.copy (i32.const 20) (i32.const 22) (i32.const 4))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.copy (i32.const 25) (i32.const 1) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, 3, 1, e, e,]);

mem_test("(memory.copy (i32.const 10) (i32.const 12) (i32.const 7))", [e, e, 3, 1, 4, 1, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.copy (i32.const 12) (i32.const 10) (i32.const 7))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, e, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))", [e, e, 3, 1, 4, 1, e, 2, 7, 1, 8, e, 7, 5, 2, 3, 6, e, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))", [e, e, 3, 1, 4, 1, e, e, e, e, e, e, 7, 5, 2, 9, 2, 7, e, e, e, e, e, e, e, e, e, e, e, e,]);

mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" + "memory.drop 1 \n" + "(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" + "memory.drop 3 \n" + "(memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" + "(memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" + "(memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" + "(memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" + "(memory.copy (i32.const 19) (i32.const 20) (i32.const 5))", [e, e, 3, 1, 4, 1, e, 2, 7, 1, 8, e, 7, e, 7, 5, 2, 7, e, 9, e, 7, e, 8, 8, e, e, e, e, e,]);

load(libdir + "wasm-binary.js");

function toU8(array) {
    for (b of array) assertEq(b < 256, true);
    return Uint8Array.from(array);
}

function varU32(u32) {
    assertEq(u32 >= 0, true);
    assertEq(u32 < Math.pow(2, 32), true);
    var bytes = [];
    do {
        var byte = u32 & 0x7f;

        u32 >>>= 7;

        if (u32 != 0) byte |= 0x80;


        bytes.push(byte);
    } while (u32 != 0);
    ;
    return bytes;
}

function moduleHeaderThen(rest) {
    return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest,];
}

function moduleWithSections(sectionArray) {
    var bytes = moduleHeaderThen();
    for (section of sectionArray) {
        bytes.push(section.name);

        bytes.push(...varU32(section.body.length));

        bytes.push(...section.body);
    }
    return toU8(bytes);
}

function sigSection(sigs) {
    var body = [];
    body.push(...varU32(sigs.length));
    for (sig of sigs) {
        body.push(...varU32(FuncCode));

        body.push(...varU32(sig.args.length));

        for (arg of sig.args) body.push(...varU32(arg));

        body.push(...varU32(sig.ret == VoidCode ? 0 : 1));

        if (sig.ret != VoidCode) body.push(...varU32(sig.ret));

    }
    return {
        name: typeId,
        body,
    };
}

function declSection(decls) {
    var body = [];
    body.push(...varU32(decls.length));
    for (decl of decls) body.push(...varU32(decl));
    return {
        name: functionId,
        body,
    };
}

function funcBody(func) {
    var body = varU32(func.locals.length);
    for (local of func.locals) body.push(...varU32(local));
    body = body.concat(...func.body);
    body.push(EndCode);
    body.splice(0, 0, ...varU32(body.length));
    return body;
}

function bodySection(bodies) {
    var body = varU32(bodies.length).concat(...bodies);
    return {
        name: codeId,
        body,
    };
}

function memorySection(initialSize) {
    var body = [];
    body.push(...varU32(1));
    body.push(...varU32(0x0));
    body.push(...varU32(initialSize));
    return {
        name: memoryId,
        body,
    };
}

const v2vSig = ({
    args: [],
    ret: VoidCode,
});

const v2vSigSection = sigSection([v2vSig,]);

function checkMiscPrefixed(opcode, expect_failure) {
    let binary = moduleWithSections([v2vSigSection, declSection([0,]), memorySection(1), bodySection([funcBody({
        locals: [],
        body: [0x41, 0x0, 0x41, 0x0, 0x41, 0x0, MiscPrefix, ...opcode,],
    }),]),]);
    if (expect_failure) {
        assertErrorMessage(()  => new WebAssembly.Module(binary), WebAssembly.CompileError, /unrecognized opcode/);
    } else {
        assertEq(WebAssembly.validate(binary), true);
    }
}

checkMiscPrefixed([0x0a, 0x00,], false);

checkMiscPrefixed([0x0b, 0x00,], false);

checkMiscPrefixed([0x0b, 0x80, 0x00,], false);

checkMiscPrefixed([0x13,], true);

{
    const tys = ['i32', 'f32', 'i64', 'f64',];

    const ops = ['copy', 'fill',];

    for (ty1 of tys) {
        for (ty2 of tys) {
            for (ty3 of tys) {
                for (op of ops) {
                    if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') continue;


                    let text = `(module
          (memory (export "memory") 1 1)
           (func (export "testfn")
           (memory.${op} ({ty1}.const 10) ({ty2}.const 20) ({ty3}.const 30))
          )
         )`;

                    assertErrorMessage(()  => wasmEvalText(text), WebAssembly.CompileError, /type mismatch/);
                }
            }
        }
    }
}
{
    for (op of ['copy', 'fill',]) {
        let text1 = `(module
          (memory (export "memory") 1 1)
          (func (export "testfn")
           (i32.const 10)
           (i32.const 20)
           memory.${op}
         )
        )`;

        assertErrorMessage(()  => wasmEvalText(text1), WebAssembly.CompileError, /popping value from empty stack/);

        let text2 = `(module
          (memory (export "memory") 1 1)
          (func (export "testfn")
           (i32.const 10)
           (i32.const 20)
           (i32.const 30)
           (i32.const 40)
           memory.${op}
         )
        )`;

        assertErrorMessage(()  => wasmEvalText(text2), WebAssembly.CompileError, /unused values not explicitly dropped by end of block/);
    }
}
{
    for (op of ['copy', 'fill',]) {
        let text = `(module
          (func (export "testfn")
           (memory.${op} (i32.const 10) (i32.const 20) (i32.const 30))
         )
        )`;

        assertErrorMessage(()  => wasmEvalText(text), WebAssembly.CompileError, /can't touch memory without memory/);
    }
}
function checkRange(arr, minIx, maxIxPlusOne, expectedValue) {
    for (let i = minIx;i < maxIxPlusOne;i++) {
        assertEq(arr[i], expectedValue);
    }
}

{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0x00000, 0x0FF00, 0x00);

    checkRange(b, 0x0FF00, 0x10000, 0x55);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0x00000, 0x10000, 0x00);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0x00000, 0x00001, 0x00);

    checkRange(b, 0x00001, 0x0FFFF, 0xAA);

    checkRange(b, 0x0FFFF, 0x10000, 0x00);
}
{
    let i = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn") (result i32)
         (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10))
         (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4))
         i32.const 99
       )
     )`);

    i.exports.testfn();

    let b = new Uint8Array(i.exports.memory.buffer);

    checkRange(b, 0x0, 0x12 + 0, 0x00);

    checkRange(b, 0x12 + 0, 0x12 + 3, 0x55);

    checkRange(b, 0x12 + 3, 0x12 + 7, 0xAA);

    checkRange(b, 0x12 + 7, 0x12 + 10, 0x55);

    checkRange(b, 0x12 + 10, 0x10000, 0x00);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
         (memory.copy (i32.const 9) (i32.const 10) (i32.const 5))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0, 0 + 9, 0x00);

    checkRange(b, 9, 9 + 11, 0x55);

    checkRange(b, 9 + 11, 0x10000, 0x00);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
         (memory.copy (i32.const 16) (i32.const 15) (i32.const 5))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0, 0 + 10, 0x00);

    checkRange(b, 10, 10 + 11, 0x55);

    checkRange(b, 10 + 11, 0x10000, 0x00);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000))
         (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000))
         (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0x00000, 0x08000, 0x55);

    checkRange(b, 0x08000, 0x10000, 0xAA);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))
       )
     )`);

    assertErrorMessage(()  => inst.exports.testfn(), WebAssembly.RuntimeError, /index out of bounds/);
}
{
    let inst = wasmEvalText(`(module
       (memory (export "memory") 1 1)
       (func (export "testfn")
         (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
         (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
         (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
         (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
         (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
         (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
         (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
         (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
         (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
         (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
         (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
         (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
         (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
         (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
         (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
         (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
         (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
         (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
         (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
         (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
         (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
         (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
         (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
         (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
         (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
         (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
         (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
         (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
         (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
         (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
         (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
         (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
         (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
         (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
         (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
         (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
         (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
         (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
         (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
         (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
         (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
         (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
         (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
         (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
         (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
         (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
         (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
         (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
         (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
         (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
         (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
         (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
         (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
         (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
         (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
         (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
         (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
         (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
         (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
         (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
         (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
         (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
         (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
         (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
         (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
         (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
         (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
         (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
         (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
         (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
         (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
         (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
         (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
         (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
         (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
         (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
         (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
         (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
         (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
         (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
         (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
         (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
         (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
         (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
         (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
         (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
         (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
         (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
         (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
         (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
         (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
         (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
         (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
         (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
         (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
         (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
         (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
         (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
         (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
         (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
         (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
         (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
         (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
         (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
         (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
         (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
         (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
         (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
         (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
         (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
         (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
         (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
         (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
         (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
         (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
         (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
         (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
         (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
         (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
         (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
         (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
         (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
         (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
         (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
         (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
         (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
         (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
         (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
         (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
         (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
         (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
         (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
         (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
         (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
         (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
         (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
         (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
         (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
         (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
         (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
         (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
         (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
         (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
         (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
         (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
         (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
         (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
         (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
         (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
         (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
         (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
         (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
         (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
         (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
         (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
         (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
         (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
         (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
         (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
         (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
         (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
         (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
         (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
         (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
         (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
         (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
         (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
         (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
         (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
         (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
         (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
         (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
         (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
         (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
         (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
         (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
         (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
         (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
         (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
         (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
         (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
         (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
         (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
         (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
         (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
         (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
         (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
         (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
         (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
         (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
         (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
         (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
         (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
         (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
         (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
         (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
         (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
         (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
         (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
         (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
       )
     )`);

    inst.exports.testfn();

    let b = new Uint8Array(inst.exports.memory.buffer);

    checkRange(b, 0, 124, 0);

    checkRange(b, 124, 1517, 9);

    checkRange(b, 1517, 2132, 0);

    checkRange(b, 2132, 2827, 10);

    checkRange(b, 2827, 2921, 92);

    checkRange(b, 2921, 3538, 83);

    checkRange(b, 3538, 3786, 77);

    checkRange(b, 3786, 4042, 97);

    checkRange(b, 4042, 4651, 99);

    checkRange(b, 4651, 5057, 0);

    checkRange(b, 5057, 5109, 99);

    checkRange(b, 5109, 5291, 0);

    checkRange(b, 5291, 5524, 72);

    checkRange(b, 5524, 5691, 92);

    checkRange(b, 5691, 6552, 83);

    checkRange(b, 6552, 7133, 77);

    checkRange(b, 7133, 7665, 99);

    checkRange(b, 7665, 8314, 0);

    checkRange(b, 8314, 8360, 62);

    checkRange(b, 8360, 8793, 86);

    checkRange(b, 8793, 8979, 83);

    checkRange(b, 8979, 9373, 79);

    checkRange(b, 9373, 9518, 95);

    checkRange(b, 9518, 9934, 59);

    checkRange(b, 9934, 10087, 77);

    checkRange(b, 10087, 10206, 5);

    checkRange(b, 10206, 10230, 77);

    checkRange(b, 10230, 10249, 41);

    checkRange(b, 10249, 11148, 83);

    checkRange(b, 11148, 11356, 74);

    checkRange(b, 11356, 11380, 93);

    checkRange(b, 11380, 11939, 74);

    checkRange(b, 11939, 12159, 68);

    checkRange(b, 12159, 12575, 83);

    checkRange(b, 12575, 12969, 79);

    checkRange(b, 12969, 13114, 95);

    checkRange(b, 13114, 14133, 59);

    checkRange(b, 14133, 14404, 76);

    checkRange(b, 14404, 14428, 57);

    checkRange(b, 14428, 14458, 59);

    checkRange(b, 14458, 14580, 32);

    checkRange(b, 14580, 14777, 89);

    checkRange(b, 14777, 15124, 59);

    checkRange(b, 15124, 15126, 36);

    checkRange(b, 15126, 15192, 100);

    checkRange(b, 15192, 15871, 96);

    checkRange(b, 15871, 15998, 95);

    checkRange(b, 15998, 17017, 59);

    checkRange(b, 17017, 17288, 76);

    checkRange(b, 17288, 17312, 57);

    checkRange(b, 17312, 17342, 59);

    checkRange(b, 17342, 17464, 32);

    checkRange(b, 17464, 17661, 89);

    checkRange(b, 17661, 17727, 59);

    checkRange(b, 17727, 17733, 5);

    checkRange(b, 17733, 17893, 96);

    checkRange(b, 17893, 18553, 77);

    checkRange(b, 18553, 18744, 42);

    checkRange(b, 18744, 18801, 76);

    checkRange(b, 18801, 18825, 57);

    checkRange(b, 18825, 18876, 59);

    checkRange(b, 18876, 18885, 77);

    checkRange(b, 18885, 18904, 41);

    checkRange(b, 18904, 19567, 83);

    checkRange(b, 19567, 20403, 96);

    checkRange(b, 20403, 21274, 77);

    checkRange(b, 21274, 21364, 100);

    checkRange(b, 21364, 21468, 74);

    checkRange(b, 21468, 21492, 93);

    checkRange(b, 21492, 22051, 74);

    checkRange(b, 22051, 22480, 68);

    checkRange(b, 22480, 22685, 100);

    checkRange(b, 22685, 22694, 68);

    checkRange(b, 22694, 22821, 10);

    checkRange(b, 22821, 22869, 100);

    checkRange(b, 22869, 24107, 97);

    checkRange(b, 24107, 24111, 37);

    checkRange(b, 24111, 24236, 77);

    checkRange(b, 24236, 24348, 72);

    checkRange(b, 24348, 24515, 92);

    checkRange(b, 24515, 24900, 83);

    checkRange(b, 24900, 25136, 95);

    checkRange(b, 25136, 25182, 85);

    checkRange(b, 25182, 25426, 68);

    checkRange(b, 25426, 25613, 89);

    checkRange(b, 25613, 25830, 96);

    checkRange(b, 25830, 26446, 100);

    checkRange(b, 26446, 26517, 10);

    checkRange(b, 26517, 27468, 92);

    checkRange(b, 27468, 27503, 95);

    checkRange(b, 27503, 27573, 77);

    checkRange(b, 27573, 28245, 92);

    checkRange(b, 28245, 28280, 95);

    checkRange(b, 28280, 29502, 77);

    checkRange(b, 29502, 29629, 42);

    checkRange(b, 29629, 30387, 83);

    checkRange(b, 30387, 30646, 77);

    checkRange(b, 30646, 31066, 92);

    checkRange(b, 31066, 31131, 77);

    checkRange(b, 31131, 31322, 42);

    checkRange(b, 31322, 31379, 76);

    checkRange(b, 31379, 31403, 57);

    checkRange(b, 31403, 31454, 59);

    checkRange(b, 31454, 31463, 77);

    checkRange(b, 31463, 31482, 41);

    checkRange(b, 31482, 31649, 83);

    checkRange(b, 31649, 31978, 72);

    checkRange(b, 31978, 32145, 92);

    checkRange(b, 32145, 32530, 83);

    checkRange(b, 32530, 32766, 95);

    checkRange(b, 32766, 32812, 85);

    checkRange(b, 32812, 33056, 68);

    checkRange(b, 33056, 33660, 89);

    checkRange(b, 33660, 33752, 59);

    checkRange(b, 33752, 33775, 36);

    checkRange(b, 33775, 33778, 32);

    checkRange(b, 33778, 34603, 9);

    checkRange(b, 34603, 35218, 0);

    checkRange(b, 35218, 35372, 10);

    checkRange(b, 35372, 35486, 77);

    checkRange(b, 35486, 35605, 5);

    checkRange(b, 35605, 35629, 77);

    checkRange(b, 35629, 35648, 41);

    checkRange(b, 35648, 36547, 83);

    checkRange(b, 36547, 36755, 74);

    checkRange(b, 36755, 36767, 93);

    checkRange(b, 36767, 36810, 83);

    checkRange(b, 36810, 36839, 100);

    checkRange(b, 36839, 37444, 96);

    checkRange(b, 37444, 38060, 100);

    checkRange(b, 38060, 38131, 10);

    checkRange(b, 38131, 39082, 92);

    checkRange(b, 39082, 39117, 95);

    checkRange(b, 39117, 39187, 77);

    checkRange(b, 39187, 39859, 92);

    checkRange(b, 39859, 39894, 95);

    checkRange(b, 39894, 40257, 77);

    checkRange(b, 40257, 40344, 89);

    checkRange(b, 40344, 40371, 59);

    checkRange(b, 40371, 40804, 77);

    checkRange(b, 40804, 40909, 5);

    checkRange(b, 40909, 42259, 92);

    checkRange(b, 42259, 42511, 77);

    checkRange(b, 42511, 42945, 83);

    checkRange(b, 42945, 43115, 77);

    checkRange(b, 43115, 43306, 42);

    checkRange(b, 43306, 43363, 76);

    checkRange(b, 43363, 43387, 57);

    checkRange(b, 43387, 43438, 59);

    checkRange(b, 43438, 43447, 77);

    checkRange(b, 43447, 43466, 41);

    checkRange(b, 43466, 44129, 83);

    checkRange(b, 44129, 44958, 96);

    checkRange(b, 44958, 45570, 77);

    checkRange(b, 45570, 45575, 92);

    checkRange(b, 45575, 45640, 77);

    checkRange(b, 45640, 45742, 42);

    checkRange(b, 45742, 45832, 72);

    checkRange(b, 45832, 45999, 92);

    checkRange(b, 45999, 46384, 83);

    checkRange(b, 46384, 46596, 95);

    checkRange(b, 46596, 46654, 92);

    checkRange(b, 46654, 47515, 83);

    checkRange(b, 47515, 47620, 77);

    checkRange(b, 47620, 47817, 79);

    checkRange(b, 47817, 47951, 95);

    checkRange(b, 47951, 48632, 100);

    checkRange(b, 48632, 48699, 97);

    checkRange(b, 48699, 48703, 37);

    checkRange(b, 48703, 49764, 77);

    checkRange(b, 49764, 49955, 42);

    checkRange(b, 49955, 50012, 76);

    checkRange(b, 50012, 50036, 57);

    checkRange(b, 50036, 50087, 59);

    checkRange(b, 50087, 50096, 77);

    checkRange(b, 50096, 50115, 41);

    checkRange(b, 50115, 50370, 83);

    checkRange(b, 50370, 51358, 92);

    checkRange(b, 51358, 51610, 77);

    checkRange(b, 51610, 51776, 83);

    checkRange(b, 51776, 51833, 89);

    checkRange(b, 51833, 52895, 100);

    checkRange(b, 52895, 53029, 97);

    checkRange(b, 53029, 53244, 68);

    checkRange(b, 53244, 54066, 100);

    checkRange(b, 54066, 54133, 97);

    checkRange(b, 54133, 54137, 37);

    checkRange(b, 54137, 55198, 77);

    checkRange(b, 55198, 55389, 42);

    checkRange(b, 55389, 55446, 76);

    checkRange(b, 55446, 55470, 57);

    checkRange(b, 55470, 55521, 59);

    checkRange(b, 55521, 55530, 77);

    checkRange(b, 55530, 55549, 41);

    checkRange(b, 55549, 56212, 83);

    checkRange(b, 56212, 57048, 96);

    checkRange(b, 57048, 58183, 77);

    checkRange(b, 58183, 58202, 41);

    checkRange(b, 58202, 58516, 83);

    checkRange(b, 58516, 58835, 95);

    checkRange(b, 58835, 58855, 77);

    checkRange(b, 58855, 59089, 95);

    checkRange(b, 59089, 59145, 77);

    checkRange(b, 59145, 59677, 99);

    checkRange(b, 59677, 60134, 0);

    checkRange(b, 60134, 60502, 89);

    checkRange(b, 60502, 60594, 59);

    checkRange(b, 60594, 60617, 36);

    checkRange(b, 60617, 60618, 32);

    checkRange(b, 60618, 60777, 42);

    checkRange(b, 60777, 60834, 76);

    checkRange(b, 60834, 60858, 57);

    checkRange(b, 60858, 60909, 59);

    checkRange(b, 60909, 60918, 77);

    checkRange(b, 60918, 60937, 41);

    checkRange(b, 60937, 61600, 83);

    checkRange(b, 61600, 62436, 96);

    checkRange(b, 62436, 63307, 77);

    checkRange(b, 63307, 63397, 100);

    checkRange(b, 63397, 63501, 74);

    checkRange(b, 63501, 63525, 93);

    checkRange(b, 63525, 63605, 74);

    checkRange(b, 63605, 63704, 100);

    checkRange(b, 63704, 63771, 97);

    checkRange(b, 63771, 63775, 37);

    checkRange(b, 63775, 64311, 77);

    checkRange(b, 64311, 64331, 26);

    checkRange(b, 64331, 64518, 92);

    checkRange(b, 64518, 64827, 11);

    checkRange(b, 64827, 64834, 26);

    checkRange(b, 64834, 65536, 0);
}
// Check that setters throw TypeError when passed no arguments, instead of crashing.

function check(obj) {
  let proto = Object.getPrototypeOf(obj);
  let props = Object.getOwnPropertyNames(proto);
  for (let prop of props) {
    let desc = Object.getOwnPropertyDescriptor(proto, prop);
    if (desc.set) {
      print("bleah: " + uneval(prop));
      assertEq(typeof desc.set, 'function');
      try {
        desc.set.call(obj);
        assertEq("should have thrown TypeError", false);
      } catch (e) {
        assertEq(e instanceof TypeError, true);
      }
    }
  }
}

var dbg = new Debugger;
var g = newGlobal();
var gw = dbg.addDebuggee(g);

// Debugger
check(dbg);

// Debugger.Memory
check(dbg.memory);

// Debugger.Object
g.eval('function f() { debugger; }');
var fw = gw.getOwnPropertyDescriptor('f').value;
check(fw);

// Debugger.Script
check(fw.script);

// Debugger.Source
check(fw.script.source);

// Debugger.Environment
check(fw.environment);

// Debugger.Frame
var log = '';
dbg.onDebuggerStatement = function(frame) {
  log += 'd';
  check(frame);
}
g.eval('f()');
assertEq(log, 'd');

vs

function check(obj) {
    let proto = Object.getPrototypeOf(obj);
    let props = Object.getOwnPropertyNames(proto);
    for (prop of props) {
        let desc = Object.getOwnPropertyDescriptor(proto, prop);

        if (desc.set) {
            print("bleah: " + uneval(prop));

            assertEq(typeof desc.set, 'function');

            try {
                desc.set.call(obj);

                assertEq("should have thrown TypeError", false);
            } catch (e) {
                assertEq(e instanceof TypeError, true);
            }
        }
    }
}

var dbg = new Debugger();

var g = newGlobal();

var gw = dbg.addDebuggee(g);

check(dbg);

check(dbg.memory);

g.eval('function f() { debugger; }');

var fw = gw.getOwnPropertyDescriptor('f').value;

check(fw);

check(fw.script);

check(fw.script.source);

check(fw.environment);

var log = '';

dbg.onDebuggerStatement = (function(frame) {
    log += 'd';
    check(frame);
});

g.eval('f()');

assertEq(log, 'd');
// Forward to the target if the trap is not defined
var proto = Object.create(null, {
    a: {
        enumerable: true,
        configurable: true
    },
    b: {
        enumerable: false,
        configurable: true
    }
});
var target = Object.create(proto, {
    c: {
        enumerable: true,
        configurable: true
    },
    d: {
        enumerable: false,
        configurable: true
    }
});

for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
    var names = Object.keys(p);
    assertEq(names.length, 1);
    assertEq(names[0], 'c');
}

vs

var proto = Object.create(null, ({
    a: ({
        enumerable: true,
        configurable: true,
    }),
    b: ({
        enumerable: false,
        configurable: true,
    }),
}));

var target = Object.create(proto, ({
    c: ({
        enumerable: true,
        configurable: true,
    }),
    d: ({
        enumerable: false,
        configurable: true,
    }),
}));

for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy,]) {
    var names = Object.keys(p);

    assertEq(names.length, 1);

    assertEq(names[0], 'c');
}
// For perf reasons we don't recompile all a debuggee global's scripts when
// Debugger no longer needs to observe all execution for that global. Test that
// things don't crash if we try to run a script with a BaselineScript that was
// compiled with debug instrumentation when the global is no longer a debuggee.

var g = newGlobal();
var dbg = new Debugger(g);
var counter = 0;
dbg.onDebuggerStatement = function (frame) {
  counter++;
  if (counter == 15)
    dbg.onDebuggerStatement = undefined;
};

g.eval("" + function f() {
  {
    let inner = 42;
    debugger;
    inner++;
  }
});
g.eval("for (var i = 0; i < 20; i++) f()");

vs

var g = newGlobal();

var dbg = new Debugger(g);

var counter = 0;

dbg.onDebuggerStatement = (function(frame) {
    counter++;
    if (counter == 15) dbg.onDebuggerStatement = undefined;

});

g.eval("" + (function f() {
    {
        let inner = 42;

        debugger;;

        inner++;
    }}));

g.eval("for (var i = 0; i < 20; i++) f()");
a = [];
for (var i = 0; i < 1000; i++) {
  a[i] = i;
}
function foo(x) {
  for (var i in x) {
  }
}
if (typeof schedulegc != "undefined")
  schedulegc(100);
foo(a);

vs

a = [];

for (let i = 0;i < 1000;i++) {
    a[i] = i;
}

function foo(x) {
    for (i in x) { 
        
    }
}

if (typeof schedulegc != "undefined") schedulegc(100);


foo(a);
// When a generator frame is resumed, the onEnterFrame fires again.
// The same Frame object is passed.

let g = newGlobal();
g.eval(`
    function* easyMode() {}

    function* f() { yield* "XYZ"; }
    function* hardMode() {
        for (let c1 of "AB")
            for (let c2 of f())
                yield c1 + c2;
    }
`);

function test(mode, expected) {
    let dbg = new Debugger(g);
    let nextid = 1;
    dbg.onEnterFrame = frame => {
        if (frame.type == "call") {
            if (!("id" in frame))
                frame.id = nextid++;
            g.log += frame.id + "(";

            frame.onPop = rv => {
                g.log += ")";
            };
        }
    };

    g.log = "";
    g.eval(`
        for (let x of ${mode}())
            log += x;
    `);
    assertEq(g.log, expected);
    dbg.enabled = false;
}

// We fire onEnterFrame for the initial activation when a generator is first
// called, even though the initial yield happens before any body code. This is
// weird but at least it's consistent.
test("easyMode", "1()1()");
test("hardMode", "1()1(2()2())AX1(2())AY1(2())AZ1(2()3()3())BX1(3())BY1(3())BZ1(3())");

vs

let g = newGlobal();

g.eval(`
    function* easyMode() {}

    function* f() { yield* "XYZ"; }
    function* hardMode() {
        for (let c1 of "AB")
            for (let c2 of f())
                yield c1 + c2;
    }
`);

function test(mode, expected) {
    let dbg = new Debugger(g);
    let nextid = 1;
    dbg.onEnterFrame = frame => {
        if (frame.type == "call") {
            if (!"id" in frame) frame.id = nextid++;


            g.log += frame.id + "(";

            frame.onPop = rv => {
                g.log += ")";
            };
        }
    };
    g.log = "";
    g.eval(`
        for (let x of ${mode}())
            log += x;
    `);
    assertEq(g.log, expected);
    dbg.enabled = false;
}

test("easyMode", "1()1()");

test("hardMode", "1()1(2()2())AX1(2())AY1(2())AZ1(2()3()3())BX1(3())BY1(3())BZ1(3())");
load(libdir + "asserts.js");

var g = newGlobal();
for (var cls of [Map, Set]) {
    var getter = Object.getOwnPropertyDescriptor(cls.prototype, "size").get;
    assertThrowsInstanceOf(function () { getter.apply(g, []); }, g.TypeError);
}

vs

load(libdir + "asserts.js");

var g = newGlobal();

for (cls of [Map, Set,]) {
    var getter = Object.getOwnPropertyDescriptor(cls.prototype, "size").get;

    assertThrowsInstanceOf(function() {
        getter.apply(g, []);
    }, g.TypeError);
}
// onEnterFrame fires after the [[GeneratorState]] is set to "executing".
//
// This test checks that Debugger doesn't accidentally make it possible to
// reenter a generator frame that's already on the stack. (Also tests a fun
// corner case in baseline debug-mode OSR.)

load(libdir + "asserts.js");

let g = newGlobal();
g.eval('function* f() { yield 1; yield 2; }');
let dbg = Debugger(g);
let genObj = null;
let hits = 0;
dbg.onEnterFrame = frame => {
    // The first time onEnterFrame fires, there is no generator object, so
    // there's nothing to test. The generator object doesn't exist until
    // JSOP_GENERATOR is reached, right before the initial yield.
    if (genObj !== null) {
        dbg.removeDebuggee(g);  // avoid the DebuggeeWouldRun exception
        assertThrowsInstanceOf(() => genObj.next(), g.TypeError);
        dbg.addDebuggee(g);
        hits++;
    }
};
genObj = g.f();
for (let x of genObj) {}
assertEq(hits, 3);

vs

load(libdir + "asserts.js");

let g = newGlobal();

g.eval('function* f() { yield 1; yield 2; }');

let dbg = Debugger(g);

let genObj = null;

let hits = 0;

dbg.onEnterFrame = frame => {
    if (genObj !== null) {
        dbg.removeDebuggee(g);

        assertThrowsInstanceOf(()  => genObj.next(), g.TypeError);

        dbg.addDebuggee(g);

        hits++;
    }
};

genObj = g.f();

for (x of genObj) { 
    
}

assertEq(hits, 3);
// |jit-test| error: TypeError

let g = newGlobal();
let dbg = Debugger(g);

let forceException = g.eval(`
    (class extends class {} {
        // Calling this will return a primitive immediately.
        constructor() {
            debugger;
            return {};
        }
    })
`);

let handler = {
    hit() {
        return {
            // Force the return of an illegal value.
            return: 1
        }
    }
};

dbg.onDebuggerStatement = function(frame) {
    var line0 = frame.script.getOffsetLocation(frame.offset).lineNumber;
    var offs = frame.script.getLineOffsets(line0 + 1);
    frame.script.setBreakpoint(offs[0], handler);
}

new forceException;

vs

let g = newGlobal();

let dbg = Debugger(g);

let forceException = g.eval(`
    (class extends class {} {
        // Calling this will return a primitive immediately.
        constructor() {
            debugger;
            return {};
        }
    })
`);

let handler = ({
    hit: (function() {
        return {
            return: 1,
        };
    }),
});

dbg.onDebuggerStatement = (function(frame) {
    var line0 = frame.script.getOffsetLocation(frame.offset).lineNumber;
    var offs = frame.script.getLineOffsets(line0 + 1);
    frame.script.setBreakpoint(offs[0], handler);
});

new forceException();
// Forward to the target if the trap is not defined
var target = {};
Object.defineProperty(target, 'foo', {
    value: 'bar',
    writable: true,
    enumerable: false,
    configurable: true
});

for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
    var desc = Object.getOwnPropertyDescriptor(p, 'foo');
    assertEq(desc.value, 'bar');
    assertEq(desc.writable, true);
    assertEq(desc.enumerable, false);
    assertEq(desc.configurable, true);
}

var proto = {};
Object.defineProperty(proto, 'foo', {
    value: 'bar',
    writable: true,
    enumerable: false,
    configurable: true
});
var target = Object.create(proto);
for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy])
    assertEq(Object.getOwnPropertyDescriptor(p, 'foo'), undefined);

vs

var target = ({});

Object.defineProperty(target, 'foo', ({
    value: 'bar',
    writable: true,
    enumerable: false,
    configurable: true,
}));

for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy,]) {
    var desc = Object.getOwnPropertyDescriptor(p, 'foo');

    assertEq(desc.value, 'bar');

    assertEq(desc.writable, true);

    assertEq(desc.enumerable, false);

    assertEq(desc.configurable, true);
}

var proto = ({});

Object.defineProperty(proto, 'foo', ({
    value: 'bar',
    writable: true,
    enumerable: false,
    configurable: true,
}));

var target = Object.create(proto);

for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy,]) assertEq(Object.getOwnPropertyDescriptor(p, 'foo'), undefined);
// |jit-test| error: ReferenceError

for (let b in [0]) {
    let b = b ? 0 : 1
}

vs

for (b in [0,]) {
    let b = b ? 0 : 1;
}
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

setJitCompilerOption("ion.warmup.trigger", 30);

var PointType = TypedObject.uint16.array(3);
var VecPointType = PointType.array(3);

function foo() {
  for (var i = 0; i < 5000; i += 10) {
    var vec = new VecPointType();

    var i0 = i % 3;
    var i1 = (i+1) % 3;
    var i2 = (i+2) % 3;

    vec[i0][i0] = i;
    vec[i0][i1] = i+1;
    vec[i0][i2] = i+2;

    vec[i1][i0] = i+3;
    vec[i1][i1] = i+4;
    vec[i1][i2] = i+5;

    vec[i2][i0] = i+6;
    vec[i2][i1] = i+7;
    vec[i2][i2] = i+8;

    var sum = vec[i0][i0] + vec[i0][i1] + vec[i0][i2];
    assertEq(sum, 3*i + 3);
    sum = vec[i1][i0] + vec[i1][i1] + vec[i1][i2];
    assertEq(sum, 3*i + 12);
    sum = vec[i2][i0] + vec[i2][i1] + vec[i2][i2];
    assertEq(sum, 3*i + 21);
  }
}

foo();

vs

setJitCompilerOption("ion.warmup.trigger", 30);

var PointType = TypedObject.uint16.array(3);

var VecPointType = PointType.array(3);

function foo() {
    for (let i = 0;i < 5000;i += 10) {
        var vec = new VecPointType();

        var i0 = i % 3;

        var i1 = i + 1 % 3;

        var i2 = i + 2 % 3;

        vec[i0][i0] = i;

        vec[i0][i1] = i + 1;

        vec[i0][i2] = i + 2;

        vec[i1][i0] = i + 3;

        vec[i1][i1] = i + 4;

        vec[i1][i2] = i + 5;

        vec[i2][i0] = i + 6;

        vec[i2][i1] = i + 7;

        vec[i2][i2] = i + 8;

        var sum = vec[i0][i0] + vec[i0][i1] + vec[i0][i2];

        assertEq(sum, 3 * i + 3);

        sum = vec[i1][i0] + vec[i1][i1] + vec[i1][i2];

        assertEq(sum, 3 * i + 12);

        sum = vec[i2][i0] + vec[i2][i1] + vec[i2][i2];

        assertEq(sum, 3 * i + 21);
    }
}

foo();
Object.extend = function(destination, source) {
    for (var property in source)
        destination[property] = source[property];
};
var Enumerable = {
    _each: function(iterator) {
        for (var i = 0, length = this.length; i < length; i++)
            iterator(this[i]);
    },
    each: function(iterator, context) {
        var index = 0;
        this._each(function(value) {
            iterator.call(context, value, index++);
        });
    },
    map: function(iterator, context) {
        var results = [];
        this.each(function(value, index) {
            var res = iterator.call(context, value);
            results.push(res);
        });
        return results;
    },
    invoke: function(method) {
        var args = $A(arguments).slice(1);
        return this.map(function(value) {
            return value[method].apply(value, args);
        });
    },
};
Object.extend(Array.prototype, Enumerable);
function $A(iterable) {
    var length = iterable.length || 0, results = new Array(length);
    while (length--) results[length] = iterable[length];
    return results;
}
function g() {
    return [1, 2, 3, 4, 5].each(function(part) {
        return 0;
    });
}
function f() {
    g();
    g();
    g();
    g();
    var result = [[2, 1, 3], [6, 5, 4]];    
    result = result.invoke('invoke', 'toString', 2);
    result[0].join(', ');
};
f();

vs

Object.extend = (function(destination, source) {
    for (property in source) destination[property] = source[property];
});

var Enumerable = ({
    _each: (function(iterator) {
        for (let i = 0, length = this.length;i < length;i++) iterator(this[i]);
    }),
    each: (function(iterator, context) {
        var index = 0;
        this._each(function(value) {
            iterator.call(context, value, index++);
        });
    }),
    map: (function(iterator, context) {
        var results = [];
        this.each(function(value, index) {
            var res = iterator.call(context, value);
            results.push(res);
        });
        return results;
    }),
    invoke: (function(method) {
        var args = $A(arguments).slice(1);
        return this.map(function(value) {
            return value[method].apply(value, args);
        });
    }),
});

Object.extend(Array.prototype, Enumerable);

function $A(iterable) {
    var length = iterable.length || 0, results = new Array(length);
    while (length--) results[length] = iterable[length];
    return results;
}

function g() {
    return [1, 2, 3, 4, 5,].each(function(part) {
        return 0;
    });
}

function f() {
    g();
    g();
    g();
    g();
    var result = [[2, 1, 3,], [6, 5, 4,],];
    result = result.invoke('invoke', 'toString', 2);
    result[0].join(', ');
}

;

f();
// Test that new.target is acceptably usable in RematerializedFrames.

gczeal(0);

load(libdir + "jitopts.js");

if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
  quit();

withJitOptions(Opts_Ion2NoOffthreadCompilation, function () {
  var g = newGlobal();
  var dbg = new Debugger;

  g.toggle = function toggle(d, expected) {
    if (d) {
      dbg.addDebuggee(g);

      var frame = dbg.getNewestFrame();
      assertEq(frame.implementation, "ion");

      // the arrow function will not be constructing, even though it has a
      // new.target value.
      assertEq(frame.constructing, false);

      // CONGRATS IF THIS FAILS! You, proud saviour, have made new.target parse
      // in debug frame evals (presumably by hooking up static scope walks).
      // Uncomment the assert below for efaust's undying gratitude.
      // Note that we use .name here because of CCW nonsense.
      assertEq(frame.eval('new.target').throw.unsafeDereference().name, "SyntaxError");
      // assertEq(frame.eval('new.target').return.unsafeDereference(), expected);
    }
  };

  g.eval("" + function f(d) { new g(d, g, 15); });

  g.eval("" + function g(d, expected) { (() => toggle(d, expected))(); });

  g.eval("(" + function test() {
    for (var i = 0; i < 5; i++)
      f(false);
    f(true);
  } + ")();");
});

vs

gczeal(0);

load(libdir + "jitopts.js");

if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation)) quit();


withJitOptions(Opts_Ion2NoOffthreadCompilation, (function() {
    var g = newGlobal();
    var dbg = new Debugger();
    g.toggle = function toggle(d, expected) {
        if (d) {
            dbg.addDebuggee(g);

            var frame = dbg.getNewestFrame();

            assertEq(frame.implementation, "ion");

            assertEq(frame.constructing, false);

            assertEq(frame.eval('new.target').throw.unsafeDereference().name, "SyntaxError");
        }
    };
    g.eval("" + function f(d) {
        new g(d, g, 15);
    });
    g.eval("" + function g(d, expected) {
        ()  => toggle(d, expected)();
    });
    g.eval("(" + function test() {
        for (let i = 0;i < 5;i++) f(false);
        f(true);
    } + ")();");
}));
load(libdir + "asserts.js");

function testProxy(handlerReturn, prop, shouldThrow) {
    var handler = { get: function () { return handlerReturn; } };
    for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
        if (shouldThrow)
            assertThrowsInstanceOf(function () { return p[prop]; }, TypeError);
        else
            assertEq(p[prop], handlerReturn);
    }
}

/*
 * Throw a TypeError if the trap reports a different value for a non-writable,
 * non-configurable property
 */
var target = {};
Object.defineProperty(target, 'foo', {
    value: 'bar',
    writable: false,
    configurable: false
});
testProxy('baz', 'foo', true);
/*
 * Don't throw a TypeError if the trap reports the same value for a non-writable,
 * non-configurable property
 */
testProxy('bar', 'foo', false);

/*
 * Don't throw a TypeError if the trap reports a different value for a writable,
 * non-configurable property
 */
Object.defineProperty(target, 'prop', {
    value: 'bar',
    writable: true,
    configurable: false
});
testProxy('baz', 'prop', false);

/*
 * Don't throw a TypeError if the trap reports a different value for a non-writable,
 * configurable property
 */
Object.defineProperty(target, 'prop2', {
    value: 'bar',
    writable: false,
    configurable: true
});
testProxy('baz', 'prop2', false);

vs

load(libdir + "asserts.js");

function testProxy(handlerReturn, prop, shouldThrow) {
    var handler = {
        get: function() {
            return handlerReturn;
        },
    };
    for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
        if (shouldThrow) assertThrowsInstanceOf(function() {
            return p[prop];
        }, TypeError);
 else assertEq(p[prop], handlerReturn);

    }
}

var target = ({});

Object.defineProperty(target, 'foo', ({
    value: 'bar',
    writable: false,
    configurable: false,
}));

testProxy('baz', 'foo', true);

testProxy('bar', 'foo', false);

Object.defineProperty(target, 'prop', ({
    value: 'bar',
    writable: true,
    configurable: false,
}));

testProxy('baz', 'prop', false);

Object.defineProperty(target, 'prop2', ({
    value: 'bar',
    writable: false,
    configurable: true,
}));

testProxy('baz', 'prop2', false);
// Test that on->off->on and off->on->off toggles don't crash.

function addRemove(dbg, g) {
  dbg.addDebuggee(g);
  var f = dbg.getNewestFrame();
  while (f)
    f = f.older;
  dbg.removeDebuggee(g);
}

function removeAdd(dbg, g) {
  dbg.removeDebuggee(g);
  dbg.addDebuggee(g);
  var f = dbg.getNewestFrame();
  while (f)
    f = f.older;
}

function newGlobalDebuggerPair(toggleSeq) {
  var g = newGlobal();
  var dbg = new Debugger;

  if (toggleSeq == removeAdd)
    dbg.addDebuggee(g);

  g.eval("" + function f() { return g(); });
  g.eval("" + function g() { return h(); });
  g.eval("line0 = Error().lineNumber;");
  g.eval("" + function h() {
    for (var i = 0; i < 100; i++)
      interruptIf(i == 95);
    debugger;
    return i;
  });

  setInterruptCallback(function () { return true; });

  return [g, dbg];
}

function testInterrupt(toggleSeq) {
  var [g, dbg] = newGlobalDebuggerPair(toggleSeq);

  setInterruptCallback(function () {
    toggleSeq(dbg, g);
    return true;
  });

  assertEq(g.f(), 100);
}

function testPrologue(toggleSeq) {
  var [g, dbg] = newGlobalDebuggerPair(toggleSeq);

  dbg.onEnterFrame = function (f) {
    if (f.callee && f.callee.name == "h")
      toggleSeq(dbg, g);
  };

  assertEq(g.f(), 100);
}

function testEpilogue(toggleSeq) {
  var [g, dbg] = newGlobalDebuggerPair(toggleSeq);

  dbg.onEnterFrame = function (f) {
    if (f.callee && f.callee.name == "h") {
      f.onPop = function () {
        toggleSeq(dbg, g);
      };
    }
  };

  assertEq(g.f(), 100);
}

function testTrap(toggleSeq) {
  var [g, dbg] = newGlobalDebuggerPair(toggleSeq);

  dbg.onEnterFrame = function (f) {
    if (f.callee && f.callee.name == "h") {
      var offs = f.script.getLineOffsets(g.line0 + 2);
      assertEq(offs.length > 0, true);
      f.script.setBreakpoint(offs[0], { hit: function () {
        toggleSeq(dbg, g);
      }});
    }
  };

  assertEq(g.f(), 100);
}

function testDebugger(toggleSeq) {
 var [g, dbg] = newGlobalDebuggerPair(toggleSeq);

  dbg.onDebuggerStatement = function () {
    toggleSeq(dbg, g);
  };

  assertEq(g.f(), 100);
}

testInterrupt(addRemove);
testInterrupt(removeAdd);

testPrologue(removeAdd);
testEpilogue(removeAdd);
testTrap(removeAdd);
testDebugger(removeAdd);

vs

function addRemove(dbg, g) {
    dbg.addDebuggee(g);
    var f = dbg.getNewestFrame();
    while (f) f = f.older;
    dbg.removeDebuggee(g);
}

function removeAdd(dbg, g) {
    dbg.removeDebuggee(g);
    dbg.addDebuggee(g);
    var f = dbg.getNewestFrame();
    while (f) f = f.older;
}

function newGlobalDebuggerPair(toggleSeq) {
    var g = newGlobal();
    var dbg = new Debugger();
    if (toggleSeq == removeAdd) dbg.addDebuggee(g);

    g.eval("" + function f() {
        return g();
    });
    g.eval("" + function g() {
        return h();
    });
    g.eval("line0 = Error().lineNumber;");
    g.eval("" + function h() {
        for (let i = 0;i < 100;i++) interruptIf(i == 95);
        debugger;;
        return i;
    });
    setInterruptCallback(function() {
        return true;
    });
    return [g, dbg,];
}

function testInterrupt(toggleSeq) {
    var [g,dbg,] = newGlobalDebuggerPair(toggleSeq);
    setInterruptCallback(function() {
        toggleSeq(dbg, g);
        return true;
    });
    assertEq(g.f(), 100);
}

function testPrologue(toggleSeq) {
    var [g,dbg,] = newGlobalDebuggerPair(toggleSeq);
    dbg.onEnterFrame = function(f) {
        if (f.callee && f.callee.name == "h") toggleSeq(dbg, g);

    };
    assertEq(g.f(), 100);
}

function testEpilogue(toggleSeq) {
    var [g,dbg,] = newGlobalDebuggerPair(toggleSeq);
    dbg.onEnterFrame = function(f) {
        if (f.callee && f.callee.name == "h") {
            f.onPop = function() {
                toggleSeq(dbg, g);
            };
        }
    };
    assertEq(g.f(), 100);
}

function testTrap(toggleSeq) {
    var [g,dbg,] = newGlobalDebuggerPair(toggleSeq);
    dbg.onEnterFrame = function(f) {
        if (f.callee && f.callee.name == "h") {
            var offs = f.script.getLineOffsets(g.line0 + 2);

            assertEq(offs.length > 0, true);

            f.script.setBreakpoint(offs[0], {
                hit: function() {
                    toggleSeq(dbg, g);
                },
            });
        }
    };
    assertEq(g.f(), 100);
}

function testDebugger(toggleSeq) {
    var [g,dbg,] = newGlobalDebuggerPair(toggleSeq);
    dbg.onDebuggerStatement = function() {
        toggleSeq(dbg, g);
    };
    assertEq(g.f(), 100);
}

testInterrupt(addRemove);

testInterrupt(removeAdd);

testPrologue(removeAdd);

testEpilogue(removeAdd);

testTrap(removeAdd);

testDebugger(removeAdd);
function test() {
    var f;
    function gen() {
	f = function(){}
    }
    for (var i in gen()) {}
    arguments[arguments.length - 1];
}
test();

vs

function test() {
    var f;
    function gen() {
        f = function() { };
    }
    for (i in gen()) { 
        
    }
    arguments[arguments.length - 1];
}

test();
let __v_11662 = `(function module() { "use asm";function foo(`;
const __v_11663 =
551;
for (let __v_11665 = 0; __v_11665 < __v_11663; ++__v_11665) {
    __v_11662 += `arg${__v_11665},`;
}
try {
  __v_11662 += `arg${__v_11663}){`;
} catch (e) {}
for (let __v_11666 = 0; __v_11666 <= __v_11663; ++__v_11666) {
    __v_11662 += `arg${__v_11666}=+arg${__v_11666};`;
}
  __v_11662 += "return 10;}function bar(){return foo(";
for (let __v_11667 = 0; __v_11667 < __v_11663; ++__v_11667) {
    __v_11662 += "0.0,";
}
  __v_11662 += "1.0)|0;}";
  __v_11662 += "return bar})()()";
const __v_11664 = eval(__v_11662);

vs

let __v_11662 = `(function module() { "use asm";function foo(`;

const __v_11663 = 551;

for (let __v_11665 = 0;__v_11665 < __v_11663;++__v_11665) {
    __v_11662 += `arg${__v_11665},`;
}

try {
    __v_11662 += `arg${__v_11663}){`;
} catch (e) { 
    
}

for (let __v_11666 = 0;__v_11666 <= __v_11663;++__v_11666) {
    __v_11662 += `arg${__v_11666}=+arg{__v_11666};`;
}

__v_11662 += "return 10;}function bar(){return foo(";

for (let __v_11667 = 0;__v_11667 < __v_11663;++__v_11667) {
    __v_11662 += "0.0,";
}

__v_11662 += "1.0)|0;}";

__v_11662 += "return bar})()()";

const __v_11664 = eval(__v_11662);
// Distinct generator calls result in distinct Debugger.Frames.

let g = newGlobal();
g.eval(`
    function* count(n) {
        if (n > 0) {
            for (let x of count(n - 1))
                yield x;
            yield n;
        }
    }
`);

let log = "";
let dbg = Debugger(g);
let nextId = 0;
function mark(frame) {
    if (frame.id === undefined)
        frame.id = nextId++;
}
dbg.onEnterFrame = frame => {
    mark(frame);
    log += frame.id + "[";
    frame.onPop = completion => {
        mark(frame);
        log += "]" + frame.id;
    };
};


let j = 0;
for (let k of g.count(5)) {
    assertEq(k, ++j);
    log += " ";
}

assertEq(log,
         // Calling a generator function just returns a generator object
         // without running the body at all; hence "0[]0". However, this call
         // does evaluate default argument values, if any, so we do report an
         // onEnterFrame / onPop for it.
         "0[]0" +
         // Demanding the first value from the top generator forces
         // SpiderMonkey to create all five generator objects (the empty "n[]n"
         // pairs) and then demand a value from them (the longer "n[...]n"
         // substrings).
         "0[1[]11[2[]22[3[]33[4[]44[5[]55[]5]4]3]2]1]0 " +
         "0[1[2[3[4[]4]3]2]1]0 " +
         "0[1[2[3[]3]2]1]0 " +
         "0[1[2[]2]1]0 " +
         "0[1[]1]0 " +
         "0[]0");

vs

let g = newGlobal();

g.eval(`
    function* count(n) {
        if (n > 0) {
            for (let x of count(n - 1))
                yield x;
            yield n;
        }
    }
`);

let log = "";

let dbg = Debugger(g);

let nextId = 0;

function mark(frame) {
    if (frame.id === undefined) frame.id = nextId++;

}

dbg.onEnterFrame = frame => {
    mark(frame);
    log += frame.id + "[";
    frame.onPop = completion => {
        mark(frame);
        log += "]" + frame.id;
    };
};

let j = 0;

for (k of g.count(5)) {
    assertEq(k, ++j);

    log += " ";
}

assertEq(log, "0[]0" + "0[1[]11[2[]22[3[]33[4[]44[5[]55[]5]4]3]2]1]0 " + "0[1[2[3[4[]4]3]2]1]0 " + "0[1[2[3[]3]2]1]0 " + "0[1[2[]2]1]0 " + "0[1[]1]0 " + "0[]0");
// Test that OSR respect debuggeeness.

var g = newGlobal();
var dbg = new Debugger(g);

g.eval("" + function f(c) {
  if (c == 0)
    return;
  if (c == 2)
    debugger;
  f(c-1);
  acc = 0;
  for (var i = 0; i < 100; i++)
    acc += i;
});

var log = "";
dbg.onDebuggerStatement = function (frame) {
  frame.onPop = function f() { log += "p"; }
};

g.eval("f(2)");

assertEq(log, "p");

vs

var g = newGlobal();

var dbg = new Debugger(g);

g.eval("" + (function f(c) {
    if (c == 0) return;

    if (c == 2) debugger;;

    f(c - 1);
    acc = 0;
    for (let i = 0;i < 100;i++) acc += i;
}));

var log = "";

dbg.onDebuggerStatement = (function(frame) {
    frame.onPop = function f() {
        log += "p";
    };
});

g.eval("f(2)");

assertEq(log, "p");
// Tests that invocation functions work.

load(libdir + "asserts.js");
load(libdir + "debuggerNXHelper.js");

var g = newGlobal();
var dbg = new Debugger();
var gw = dbg.addDebuggee(g);

g.eval(`
       function d() { debugger; }
       function f() { return 42; }
       var o = {
         get p() { return 42; },
         set p(x) { }
       };
       `);

var strs = ["f();", "o.p", "o.p = 42"];

var fw;
dbg.onDebuggerStatement = (frame) => {
  fw = frame.arguments[0];
};
gw.executeInGlobal("d(f)");
dbg.onDebuggerStatement = undefined;

function testHook(hookName) {
  var newestFrame = dbg.getNewestFrame();
  for (var s of strs) {
    if (newestFrame) {
      assertEq(newestFrame.eval(s).return, 42);
    }
    assertEq(gw.executeInGlobal(s).return, 42);
    assertEq(fw.apply(null).return, 42);
  }
}

testDebuggerHooksNX(dbg, g, testHook);

vs

load(libdir + "asserts.js");

load(libdir + "debuggerNXHelper.js");

var g = newGlobal();

var dbg = new Debugger();

var gw = dbg.addDebuggee(g);

g.eval(`
       function d() { debugger; }
       function f() { return 42; }
       var o = {
         get p() { return 42; },
         set p(x) { }
       };
       `);

var strs = ["f();", "o.p", "o.p = 42",];

var fw;

dbg.onDebuggerStatement = frame => {
    fw = frame.arguments[0];
};

gw.executeInGlobal("d(f)");

dbg.onDebuggerStatement = undefined;

function testHook(hookName) {
    var newestFrame = dbg.getNewestFrame();
    for (s of strs) {
        if (newestFrame) {
            assertEq(newestFrame.eval(s).return, 42);
        }

        assertEq(gw.executeInGlobal(s).return, 42);

        assertEq(fw.apply(null).return, 42);
    }
}

testDebuggerHooksNX(dbg, g, testHook);
// Reflect side-effects from the trap
var target = {
    foo: 'bar'
};

var handler = { set: (target, name) => target[name] = 'qux' };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    p['foo'] = 'baz';
    assertEq(target['foo'], 'qux');

    // reset for second iteration
    target['foo'] = 'bar';
}

vs

var target = ({
    foo: 'bar',
});

var handler = ({
    set: (target, name)  => target[name] = 'qux',
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    p['foo'] = 'baz';

    assertEq(target['foo'], 'qux');

    target['foo'] = 'bar';
}
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

setJitCompilerOption("ion.warmup.trigger", 30);

var Vec3u32Type = TypedObject.uint32.array(3);
var PairVec3u32Type = new TypedObject.StructType({fst: Vec3u32Type,
                                                  snd: Vec3u32Type});

function foo_u32() {
  for (var i = 0; i < 5000; i += 10) {
    var p = new PairVec3u32Type();

    p.fst[(i)   % 3] = i;
    p.fst[(i+1) % 3] = i+1;
    p.fst[(i+2) % 3] = i+2;

    p.snd[(i)   % 3] = i+3;
    p.snd[(i+1) % 3] = i+4;
    p.snd[(i+2) % 3] = i+5;

    var sum = p.fst[0] + p.fst[1] + p.fst[2];
    assertEq(sum, 3*i + 3);
    sum = p.snd[0] + p.snd[1] + p.snd[2];
    assertEq(sum, 3*i + 12);
  }
}

foo_u32();

vs

setJitCompilerOption("ion.warmup.trigger", 30);

var Vec3u32Type = TypedObject.uint32.array(3);

var PairVec3u32Type = new TypedObject.StructType(({
    fst: Vec3u32Type,
    snd: Vec3u32Type,
}));

function foo_u32() {
    for (let i = 0;i < 5000;i += 10) {
        var p = new PairVec3u32Type();

        p.fst[i % 3] = i;

        p.fst[i + 1 % 3] = i + 1;

        p.fst[i + 2 % 3] = i + 2;

        p.snd[i % 3] = i + 3;

        p.snd[i + 1 % 3] = i + 4;

        p.snd[i + 2 % 3] = i + 5;

        var sum = p.fst[0] + p.fst[1] + p.fst[2];

        assertEq(sum, 3 * i + 3);

        sum = p.snd[0] + p.snd[1] + p.snd[2];

        assertEq(sum, 3 * i + 12);
    }
}

foo_u32();
// Binary: cache/js-dbg-32-7d06dac3fe83-linux
// Flags: -j
//
function partOfSHA1(str)
{
  var rotate_left = function (n,s) { return ( n<<s ) | (n>>>(32-s)); },
  W = [], H0 = 0x67452301,
  H1 = 0xEFCDAB89, H2 = 0x98BADCFE,
  H3 = 0x10325476, H4 = 0xC3D2E1F0,
  A, B, C, D, E, temp, str_len = str.length,
  word_array = [];
  i = 0x080000000;
  word_array.push( (str_len<<3)&0x0ffffffff );
  for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) {
    A = H0;
    B = H1;
    C = H2;
    D = H3;
    E = H4;
    for (i= 0; i<=19; ++i) {
      temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
      E = D;
      D = C;
      C = rotate_left(B,30);
      B = A;
      A = temp;
    }
  }
}

partOfSHA1(1226369254122);

vs

function partOfSHA1(str) {
    var rotate_left = function(n, s) {
        return n << s | n >>> 32 - s;
    }, W = [], H0 = 0x67452301, H1 = 0xEFCDAB89, H2 = 0x98BADCFE, H3 = 0x10325476, H4 = 0xC3D2E1F0, A, B, C, D, E, temp, str_len = str.length, word_array = [];
    i = 0x080000000;
    word_array.push(str_len << 3 & 0x0ffffffff);
    for (blockstart = 0;blockstart < word_array.length;blockstart += 16) {
        A = H0;

        B = H1;

        C = H2;

        D = H3;

        E = H4;

        for (i = 0;i <= 19;++i) {
            temp = rotate_left(A, 5) + B & C | ~B & D + E + W[i] + 0x5A827999 & 0x0ffffffff;

            E = D;

            D = C;

            C = rotate_left(B, 30);

            B = A;

            A = temp;
        }
    }
}

partOfSHA1(1226369254122);
load(libdir + "asm.js");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i+j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i+j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i-j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i-j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i*j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i*j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (i*j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0; return (i*1048576)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0; return (i*-1048576)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (i + (j*4))|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var two30 = 1073741824; return (((two30 * 524288 * 16) + 1) & 1)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i/j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i/j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=1,j=1; return (i/j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i%j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i%j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i<j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i<j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (i<j)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0.0; return (-i)|0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (-(i+j))|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i|0)/(k|0) } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i>>>0)/(k>>>0) } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i|0)%(k|0) } return f");
assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i>>>0)%(k>>>0) } return f");

const UINT32_MAX = Math.pow(2,32)-1;
const INT32_MIN = -Math.pow(2,31);
const INT32_MAX = Math.pow(2,31)-1;

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (i*2)|0 } return f"));
assertEq(f(0), 0);
assertEq(f(INT32_MIN), (2*INT32_MIN)|0);
assertEq(f(INT32_MAX), (2*INT32_MAX)|0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (2*i)|0 } return f"));
assertEq(f(0), 0);
assertEq(f(INT32_MIN), (2*INT32_MIN)|0);
assertEq(f(INT32_MAX), (2*INT32_MAX)|0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (i*1048575)|0 } return f"));
assertEq(f(0), 0);
assertEq(f(2), (1048575*2)|0);
assertEq(f(-1), (1048575*-1)|0);
assertEq(f(INT32_MIN), (1048575*INT32_MIN)|0);
assertEq(f(INT32_MAX), (1048575*INT32_MAX)|0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (1048575*i)|0 } return f"));
assertEq(f(0), 0);
assertEq(f(2), (1048575*2)|0);
assertEq(f(-1), (1048575*-1)|0);
assertEq(f(INT32_MIN), (1048575*INT32_MIN)|0);
assertEq(f(INT32_MAX), (1048575*INT32_MAX)|0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0; j=~i; return j|0 } return f"));
assertEq(f(0), ~0);
assertEq(f(3), ~3);
assertEq(f(-3), ~-3);
assertEq(f(INT32_MAX), ~INT32_MAX);
assertEq(f(INT32_MIN), ~INT32_MIN);
assertEq(f(UINT32_MAX), ~UINT32_MAX);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=+i; var j=0; j=~~i; return j|0 } return f"));
assertEq(f(0), 0);
assertEq(f(3.5), 3);
assertEq(f(-3.5), -3);
assertEq(f(INT32_MAX), INT32_MAX);
assertEq(f(INT32_MIN), INT32_MIN);
assertEq(f(UINT32_MAX), -1);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0.0; j=+~~i; return +j } return f"));
assertEq(f(0), 0);
assertEq(f(INT32_MAX), INT32_MAX);
assertEq(f(INT32_MIN), INT32_MIN);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0.1; j=+(i>>>0); return +j } return f"));
assertEq(f(0), 0);
assertEq(f(INT32_MAX), INT32_MAX);
assertEq(f(UINT32_MAX), UINT32_MAX);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (-i)|0 } return f"));
assertEq(f(0), 0);
assertEq(f(-0), 0);
assertEq(f(1), -1);
assertEq(f(INT32_MAX), INT32_MIN+1);
assertEq(f(INT32_MIN), INT32_MIN);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=+i; return +(-i) } return f"));
assertEq(f(0), -0);
assertEq(f(-0), 0);
assertEq(f(-1), 1);
assertEq(f(1), -1);
assertEq(f(Math.pow(2,50)), -Math.pow(2,50));
assertEq(f(1.54e20), -1.54e20);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i|0) < (j|0))|0 } return f"));
assertEq(f(0, 1), 1);
assertEq(f(1, 0), 0);
assertEq(f(1, 1), 0);
assertEq(f(INT32_MIN, INT32_MAX), 1);
assertEq(f(INT32_MAX, INT32_MIN), 0);
assertEq(f(0, INT32_MAX), 1);
assertEq(f(INT32_MAX, 0), 0);
assertEq(f(INT32_MIN, 0), 1);
assertEq(f(0, INT32_MIN), 0);
assertEq(f(UINT32_MAX, 0), 1);
assertEq(f(0, UINT32_MAX), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i>>>0) < (j>>>0))|0 } return f"));
assertEq(f(0, 1), 1);
assertEq(f(1, 0), 0);
assertEq(f(1, 1), 0);
assertEq(f(INT32_MIN, INT32_MAX), 0);
assertEq(f(INT32_MAX, INT32_MIN), 1);
assertEq(f(0, INT32_MAX), 1);
assertEq(f(INT32_MAX, 0), 0);
assertEq(f(INT32_MIN, 0), 0);
assertEq(f(0, INT32_MIN), 1);
assertEq(f(UINT32_MAX, 0), 0);
assertEq(f(0, UINT32_MAX), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)==(j|0); return k|0 } return f"));
assertEq(f(1,2), 0);
assertEq(f(1,1), 1);
assertEq(f(2,1), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)!=(j|0); return k|0 } return f"));
assertEq(f(1,2), 1);
assertEq(f(1,1), 0);
assertEq(f(2,1), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<(j|0); return k|0 } return f"));
assertEq(f(1,2), 1);
assertEq(f(1,1), 0);
assertEq(f(1,0), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>(j|0); return k|0 } return f"));
assertEq(f(1,2), 0);
assertEq(f(1,1), 0);
assertEq(f(1,0), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<=(j|0); return k|0 } return f"));
assertEq(f(1,2), 1);
assertEq(f(1,1), 1);
assertEq(f(1,0), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>=(j|0); return k|0 } return f"));
assertEq(f(1,2), 0);
assertEq(f(1,1), 1);
assertEq(f(1,0), 1);

assertEq(asmLink(asmCompile(USE_ASM + "const I=2; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f"))(1), 1);
assertEq(asmLink(asmCompile(USE_ASM + "const I=2; function f(i) { i=i|0; var k=0; k=(i>>>0)<I; return k|0 } return f"))(1), 1);
assertEq(asmLink(asmCompile(USE_ASM + "const I=-2; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f"))(-1), 0);
assertAsmTypeFail(USE_ASM + "const I=-2; function f(i) { i=i|0; var k=0; k=(i>>>0)<I; return k|0 } return f");
assertAsmTypeFail(USE_ASM + "const I=0x80000000; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f");

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i|0)/(j|0))|0 } return f"));
assertEq(f(4,2), 2);
assertEq(f(3,2), 1);
assertEq(f(3,-2), -1);
assertEq(f(-3,-2), 1);
assertEq(f(0, -1), 0);
assertEq(f(0, INT32_MAX), 0);
assertEq(f(0, INT32_MIN), 0);
assertEq(f(INT32_MAX, 0), 0);
assertEq(f(INT32_MIN, 0), 0);
assertEq(f(-1, INT32_MAX), 0);
assertEq(f(-1, INT32_MIN), 0);
assertEq(f(INT32_MAX, -1), -INT32_MAX);
assertEq(f(INT32_MIN, -1), INT32_MIN); // !!
assertEq(f(INT32_MAX, INT32_MAX), 1);
assertEq(f(INT32_MAX, INT32_MIN), 0);
assertEq(f(INT32_MIN, INT32_MAX), -1);
assertEq(f(INT32_MIN, INT32_MIN), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i>>>0)/(j>>>0))|0 } return f"));
assertEq(f(4,2), 2);
assertEq(f(3,2), 1);
assertEq(f(3,-2), 0);
assertEq(f(-3,-2), 0);
assertEq(f(0, -1), 0);
assertEq(f(0, INT32_MAX), 0);
assertEq(f(0, INT32_MIN), 0);
assertEq(f(0, UINT32_MAX), 0);
assertEq(f(INT32_MAX, 0), 0);
assertEq(f(INT32_MIN, 0), 0);
assertEq(f(UINT32_MAX, 0), 0);
assertEq(f(-1, INT32_MAX), 2);
assertEq(f(-1, INT32_MIN), 1);
assertEq(f(-1, UINT32_MAX), 1);
assertEq(f(INT32_MAX, -1), 0);
assertEq(f(INT32_MIN, -1), 0);
assertEq(f(UINT32_MAX, -1), 1);
assertEq(f(INT32_MAX, INT32_MAX), 1);
assertEq(f(INT32_MAX, INT32_MIN), 0);
assertEq(f(UINT32_MAX, INT32_MAX), 2);
assertEq(f(INT32_MAX, UINT32_MAX), 0);
assertEq(f(UINT32_MAX, UINT32_MAX), 1);
assertEq(f(INT32_MIN, INT32_MAX), 1);
assertEq(f(INT32_MIN, UINT32_MAX), 0);
assertEq(f(INT32_MIN, INT32_MIN), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k = 0; k = (i|0)%(j|0)|0; return k|0 } return f"));
assertEq(f(4,2), 0);
assertEq(f(3,2), 1);
assertEq(f(3,-2), 1);
assertEq(f(-3,-2), -1);
assertEq(f(0, -1), 0);
assertEq(f(0, INT32_MAX), 0);
assertEq(f(0, INT32_MIN), 0);
assertEq(f(INT32_MAX, 0), 0);
assertEq(f(INT32_MIN, 0), 0);
assertEq(f(-1, INT32_MAX), -1);
assertEq(f(-1, INT32_MIN), -1);
assertEq(f(INT32_MAX, -1), 0);
assertEq(f(INT32_MIN, -1), 0); // !!
assertEq(f(INT32_MAX, INT32_MAX), 0);
assertEq(f(INT32_MAX, INT32_MIN), INT32_MAX);
assertEq(f(INT32_MIN, INT32_MAX), -1);
assertEq(f(INT32_MIN, INT32_MIN), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k = 0; k = (i|0)%4|0; return k|0 } return f"));
assertEq(f(0), 0);
assertEq(f(-1), -1);
assertEq(f(-3), -3);
assertEq(f(-4), 0);
assertEq(f(INT32_MIN), 0);
assertEq(f(3), 3);
assertEq(f(4), 0);
assertEq(f(INT32_MAX), 3);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k = 0; k = (i>>>0)%(j>>>0)|0; return k|0 } return f"));
assertEq(f(4,2), 0);
assertEq(f(3,2), 1);
assertEq(f(3,-2), 3);
assertEq(f(-3,-2), -3);
assertEq(f(0, -1), 0);
assertEq(f(0, INT32_MAX), 0);
assertEq(f(0, INT32_MIN), 0);
assertEq(f(0, UINT32_MAX), 0);
assertEq(f(INT32_MAX, 0), 0);
assertEq(f(INT32_MIN, 0), 0);
assertEq(f(UINT32_MAX, 0), 0);
assertEq(f(-1, INT32_MAX), 1);
assertEq(f(-1, INT32_MIN), INT32_MAX);
assertEq(f(-1, UINT32_MAX), 0);
assertEq(f(INT32_MAX, -1), INT32_MAX);
assertEq(f(INT32_MIN, -1), INT32_MIN);
assertEq(f(UINT32_MAX, -1), 0);
assertEq(f(INT32_MAX, INT32_MAX), 0);
assertEq(f(INT32_MAX, INT32_MIN), INT32_MAX);
assertEq(f(UINT32_MAX, INT32_MAX), 1);
assertEq(f(INT32_MAX, UINT32_MAX), INT32_MAX);
assertEq(f(UINT32_MAX, UINT32_MAX), 0);
assertEq(f(INT32_MIN, INT32_MAX), 1);
assertEq(f(INT32_MIN, UINT32_MAX), INT32_MIN);
assertEq(f(INT32_MIN, INT32_MIN), 0);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 / 2)|0 } return f"))(), 2);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (3 / 2)|0 } return f"))(), 1);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 % 2)|0 } return f"))(), 0);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (3 % 2)|0 } return f"))(), 1);

assertAsmTypeFail(USE_ASM + "function f() { var i=42,j=1.1; return +(i?i:j) } return f");
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return 0; 1 ? 1 : 1; return 0; } return f"))(), 0);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=42,j=1.1; return +(i?+(i|0):j) } return f"))(), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=42,j=1; return (i?i:j)|0 } return f"))(), 42);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=42,j=1; return 13; return (i?i:j)|0 } return f"))(), 13);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (0 > (-(~~1) >>> 0)) | 0; } return f"))(), 0);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return 0 < 4294967294 | 0; } return f"))(), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i|0)>(j|0)?(i+10)|0:(j+100)|0)|0 } return f"));
assertEq(f(2, 4), 104);
assertEq(f(-2, -4), 8);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j,k) { i=i|0;j=j|0;k=k|0; return ((i|0)>(j|0) ? (i|0)>(k|0) ? i : k : (j|0)>(k|0) ? j : k)|0 } return f"));
assertEq(f(1,2,3), 3);
assertEq(f(1,3,2), 3);
assertEq(f(2,1,3), 3);
assertEq(f(2,3,1), 3);
assertEq(f(3,1,2), 3);
assertEq(f(3,2,1), 3);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var a=0,b=0; a=i>>>0 < 4294967292; b=(i|0) < -4; return (j ? a : b)|0 } return f"));
assertEq(f(1,true), 1);
assertEq(f(-1,true), 0);
assertEq(f(-5,true), 1);
assertEq(f(1,false), 0);
assertEq(f(-1,false), 0);
assertEq(f(-5,false), 1);

assertAsmTypeFail('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return (i32[0]+1)|0 } return f");
new Float64Array(BUF_64KB)[0] = 2.3;
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] + 2.0) } return f"), this, null, BUF_64KB)(), 2.3+2);
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] - 2.0) } return f"), this, null, BUF_64KB)(), 2.3-2);
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] * 2.0) } return f"), this, null, BUF_64KB)(), 2.3*2);
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] / 2.0) } return f"), this, null, BUF_64KB)(), 2.3/2);
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] % 2.0) } return f"), this, null, BUF_64KB)(), 2.3%2);
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "function f() { return +-f64[0] } return f"), this, null, BUF_64KB)(), -2.3);
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "var sqrt=glob.Math.sqrt; function f() { return +sqrt(f64[0]) } return f"), this, null, BUF_64KB)(), Math.sqrt(2.3));
new Int32Array(BUF_64KB)[0] = 42;
assertEq(asmLink(asmCompile('glob','imp','b', USE_ASM + HEAP_IMPORTS + "var imul=glob.Math.imul; function f() { return imul(i32[0], 2)|0 } return f"), this, null, BUF_64KB)(), 84);

// beware ye phis of comparisons and integers
var f = asmLink(asmCompile(USE_ASM + "function g(i) { i=i|0; if (i) { i = ((i|0) == 2); } else { i=(i-1)|0 } return i|0; } return g "));
assertEq(f(0), -1);
assertEq(f(1), 0);
assertEq(f(2), 1);
var f = asmLink(asmCompile(USE_ASM + "function g(i) { i=i|0; if (i) { i = !i } else { i=(i-1)|0 } return i|0; } return g "));
assertEq(f(0), -1);
assertEq(f(1), 0);
assertEq(f(2), 0);

// beware ye constant-evaluate of boolean-producing operators
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 | (2 == 2))|0 } return f"))(), 5);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 | (!2))|0 } return f"))(), 4);

// get that order-of-operations right!
var buf = new ArrayBuffer(BUF_MIN);
asmLink(asmCompile('glob','imp','buf', USE_ASM + "var i32=new glob.Int32Array(buf); var x=0; function a() { return x|0 } function b() { x=42; return 0 } function f() { i32[((b()|0) & 0x3) >> 2] = a()|0 } return f"), this, null, buf)();
assertEq(new Int32Array(buf)[0], 42);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { var a=0,i=0; for (; ~~i!=4; i=(i+1)|0) { a = (a*5)|0; if (+(a>>>0) != 0.0) return 1; } return 0; } return f"))(), 0)

// Signed integer division by a power of two.
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/1)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), Math.pow(2,i));
    assertEq(f(Math.pow(2,i)-1), Math.pow(2,i)-1);
    assertEq(f(-Math.pow(2,i)), -Math.pow(2,i));
    assertEq(f(-Math.pow(2,i)-1), -Math.pow(2,i)-1);
}
assertEq(f(INT32_MIN), INT32_MIN);
assertEq(f(INT32_MAX), INT32_MAX);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/2)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/2)|0);
    assertEq(f(Math.pow(2,i)-1), ((Math.pow(2,i)-1)/2)|0);
    assertEq(f(-Math.pow(2,i)), (-Math.pow(2,i)/2)|0);
    assertEq(f(-Math.pow(2,i)-1), ((-Math.pow(2,i)-1)/2)|0);
}
assertEq(f(INT32_MIN), (INT32_MIN/2)|0);
assertEq(f(INT32_MAX), (INT32_MAX/2)|0);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/4)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/4)|0);
    assertEq(f(Math.pow(2,i)-1), ((Math.pow(2,i)-1)/4)|0);
    assertEq(f(-Math.pow(2,i)), (-Math.pow(2,i)/4)|0);
    assertEq(f(-Math.pow(2,i)-1), ((-Math.pow(2,i)-1)/4)|0);
}
assertEq(f(INT32_MIN), (INT32_MIN/4)|0);
assertEq(f(INT32_MAX), (INT32_MAX/4)|0);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/1073741824)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/Math.pow(2,30))|0);
    assertEq(f(Math.pow(2,i)-1), ((Math.pow(2,i)-1)/Math.pow(2,30))|0);
    assertEq(f(-Math.pow(2,i)), (-Math.pow(2,i)/Math.pow(2,30))|0);
    assertEq(f(-Math.pow(2,i)-1), ((-Math.pow(2,i)-1)/Math.pow(2,30))|0);
}
assertEq(f(INT32_MIN), (INT32_MIN/Math.pow(2,30))|0);
assertEq(f(INT32_MAX), (INT32_MAX/Math.pow(2,30))|0);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((((i|0)/1)|0)+i)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i) * 2)|0);
    assertEq(f(Math.pow(2,i) - 1), ((Math.pow(2,i) - 1) * 2)|0);
    assertEq(f(-Math.pow(2,i)), (-Math.pow(2,i) * 2)|0);
    assertEq(f(-Math.pow(2,i) - 1), ((-Math.pow(2,i) - 1) * 2)|0);
}
assertEq(f(INT32_MIN), (INT32_MIN * 2)|0);
assertEq(f(INT32_MAX), (INT32_MAX * 2)|0);

// Signed integer division by a power of two - with a non-negative numerator!
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/1)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), Math.pow(2,i));
    assertEq(f(Math.pow(2,i+1)-1), Math.pow(2,i+1)-1);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/2)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/2)|0);
    assertEq(f(Math.pow(2,i+1)-1), ((Math.pow(2,i+1)-1)/2)|0);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/4)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/4)|0);
    assertEq(f(Math.pow(2,i+1)-1), ((Math.pow(2,i+1)-1)/4)|0);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/1073741824)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/Math.pow(2,30))|0);
    assertEq(f(Math.pow(2,i+1)-1), ((Math.pow(2,i+1)-1)/Math.pow(2,30))|0);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((((i|0)/1)|0)+i)|0; } return f;"));
for (let i = 0; i < 31; i++) {
    assertEq(f(Math.pow(2,i)), (Math.pow(2,i) * 2)|0);
    assertEq(f(Math.pow(2,i+1) - 1), ((Math.pow(2,i+1) - 1) * 2)|0);
}
assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f(x, y) { x = x|0; y = y|0; g = (x>>>0)%(y>>>0)|0; return (x|0)%(y|0)|0; } return f;"))(0xff40001, 0xfff80000), 0x40001);

vs

load(libdir + "asm.js");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i+j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i+j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i-j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i-j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i*j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i*j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (i*j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0; return (i*1048576)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0; return (i*-1048576)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (i + (j*4))|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var two30 = 1073741824; return (((two30 * 524288 * 16) + 1) & 1)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i/j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i/j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=1,j=1; return (i/j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i%j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i%j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i<j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i<j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (i<j)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0.0; return (-i)|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0; return (-(i+j))|0 } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i|0)/(k|0) } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i>>>0)/(k>>>0) } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i|0)%(k|0) } return f");

assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0,k=0; k = (i>>>0)%(k>>>0) } return f");

const UINT32_MAX = Math.pow(2, 32) - 1;

const INT32_MIN = -Math.pow(2, 31);

const INT32_MAX = Math.pow(2, 31) - 1;

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (i*2)|0 } return f"));

assertEq(f(0), 0);

assertEq(f(INT32_MIN), 2 * INT32_MIN | 0);

assertEq(f(INT32_MAX), 2 * INT32_MAX | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (2*i)|0 } return f"));

assertEq(f(0), 0);

assertEq(f(INT32_MIN), 2 * INT32_MIN | 0);

assertEq(f(INT32_MAX), 2 * INT32_MAX | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (i*1048575)|0 } return f"));

assertEq(f(0), 0);

assertEq(f(2), 1048575 * 2 | 0);

assertEq(f(-1), 1048575 * -1 | 0);

assertEq(f(INT32_MIN), 1048575 * INT32_MIN | 0);

assertEq(f(INT32_MAX), 1048575 * INT32_MAX | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (1048575*i)|0 } return f"));

assertEq(f(0), 0);

assertEq(f(2), 1048575 * 2 | 0);

assertEq(f(-1), 1048575 * -1 | 0);

assertEq(f(INT32_MIN), 1048575 * INT32_MIN | 0);

assertEq(f(INT32_MAX), 1048575 * INT32_MAX | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0; j=~i; return j|0 } return f"));

assertEq(f(0), ~0);

assertEq(f(3), ~3);

assertEq(f(-3), ~-3);

assertEq(f(INT32_MAX), ~INT32_MAX);

assertEq(f(INT32_MIN), ~INT32_MIN);

assertEq(f(UINT32_MAX), ~UINT32_MAX);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=+i; var j=0; j=~~i; return j|0 } return f"));

assertEq(f(0), 0);

assertEq(f(3.5), 3);

assertEq(f(-3.5), -3);

assertEq(f(INT32_MAX), INT32_MAX);

assertEq(f(INT32_MIN), INT32_MIN);

assertEq(f(UINT32_MAX), -1);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0.0; j=+~~i; return +j } return f"));

assertEq(f(0), 0);

assertEq(f(INT32_MAX), INT32_MAX);

assertEq(f(INT32_MIN), INT32_MIN);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; var j=0.1; j=+(i>>>0); return +j } return f"));

assertEq(f(0), 0);

assertEq(f(INT32_MAX), INT32_MAX);

assertEq(f(UINT32_MAX), UINT32_MAX);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return (-i)|0 } return f"));

assertEq(f(0), 0);

assertEq(f(-0), 0);

assertEq(f(1), -1);

assertEq(f(INT32_MAX), INT32_MIN + 1);

assertEq(f(INT32_MIN), INT32_MIN);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=+i; return +(-i) } return f"));

assertEq(f(0), -0);

assertEq(f(-0), 0);

assertEq(f(-1), 1);

assertEq(f(1), -1);

assertEq(f(Math.pow(2, 50)), -Math.pow(2, 50));

assertEq(f(1.54e20), -1.54e20);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i|0) < (j|0))|0 } return f"));

assertEq(f(0, 1), 1);

assertEq(f(1, 0), 0);

assertEq(f(1, 1), 0);

assertEq(f(INT32_MIN, INT32_MAX), 1);

assertEq(f(INT32_MAX, INT32_MIN), 0);

assertEq(f(0, INT32_MAX), 1);

assertEq(f(INT32_MAX, 0), 0);

assertEq(f(INT32_MIN, 0), 1);

assertEq(f(0, INT32_MIN), 0);

assertEq(f(UINT32_MAX, 0), 1);

assertEq(f(0, UINT32_MAX), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i>>>0) < (j>>>0))|0 } return f"));

assertEq(f(0, 1), 1);

assertEq(f(1, 0), 0);

assertEq(f(1, 1), 0);

assertEq(f(INT32_MIN, INT32_MAX), 0);

assertEq(f(INT32_MAX, INT32_MIN), 1);

assertEq(f(0, INT32_MAX), 1);

assertEq(f(INT32_MAX, 0), 0);

assertEq(f(INT32_MIN, 0), 0);

assertEq(f(0, INT32_MIN), 1);

assertEq(f(UINT32_MAX, 0), 0);

assertEq(f(0, UINT32_MAX), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)==(j|0); return k|0 } return f"));

assertEq(f(1, 2), 0);

assertEq(f(1, 1), 1);

assertEq(f(2, 1), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)!=(j|0); return k|0 } return f"));

assertEq(f(1, 2), 1);

assertEq(f(1, 1), 0);

assertEq(f(2, 1), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<(j|0); return k|0 } return f"));

assertEq(f(1, 2), 1);

assertEq(f(1, 1), 0);

assertEq(f(1, 0), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>(j|0); return k|0 } return f"));

assertEq(f(1, 2), 0);

assertEq(f(1, 1), 0);

assertEq(f(1, 0), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)<=(j|0); return k|0 } return f"));

assertEq(f(1, 2), 1);

assertEq(f(1, 1), 1);

assertEq(f(1, 0), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k=0; k=(i|0)>=(j|0); return k|0 } return f"));

assertEq(f(1, 2), 0);

assertEq(f(1, 1), 1);

assertEq(f(1, 0), 1);

assertEq(asmLink(asmCompile(USE_ASM + "const I=2; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f"))(1), 1);

assertEq(asmLink(asmCompile(USE_ASM + "const I=2; function f(i) { i=i|0; var k=0; k=(i>>>0)<I; return k|0 } return f"))(1), 1);

assertEq(asmLink(asmCompile(USE_ASM + "const I=-2; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f"))(-1), 0);

assertAsmTypeFail(USE_ASM + "const I=-2; function f(i) { i=i|0; var k=0; k=(i>>>0)<I; return k|0 } return f");

assertAsmTypeFail(USE_ASM + "const I=0x80000000; function f(i) { i=i|0; var k=0; k=(i|0)<I; return k|0 } return f");

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i|0)/(j|0))|0 } return f"));

assertEq(f(4, 2), 2);

assertEq(f(3, 2), 1);

assertEq(f(3, -2), -1);

assertEq(f(-3, -2), 1);

assertEq(f(0, -1), 0);

assertEq(f(0, INT32_MAX), 0);

assertEq(f(0, INT32_MIN), 0);

assertEq(f(INT32_MAX, 0), 0);

assertEq(f(INT32_MIN, 0), 0);

assertEq(f(-1, INT32_MAX), 0);

assertEq(f(-1, INT32_MIN), 0);

assertEq(f(INT32_MAX, -1), -INT32_MAX);

assertEq(f(INT32_MIN, -1), INT32_MIN);

assertEq(f(INT32_MAX, INT32_MAX), 1);

assertEq(f(INT32_MAX, INT32_MIN), 0);

assertEq(f(INT32_MIN, INT32_MAX), -1);

assertEq(f(INT32_MIN, INT32_MIN), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i>>>0)/(j>>>0))|0 } return f"));

assertEq(f(4, 2), 2);

assertEq(f(3, 2), 1);

assertEq(f(3, -2), 0);

assertEq(f(-3, -2), 0);

assertEq(f(0, -1), 0);

assertEq(f(0, INT32_MAX), 0);

assertEq(f(0, INT32_MIN), 0);

assertEq(f(0, UINT32_MAX), 0);

assertEq(f(INT32_MAX, 0), 0);

assertEq(f(INT32_MIN, 0), 0);

assertEq(f(UINT32_MAX, 0), 0);

assertEq(f(-1, INT32_MAX), 2);

assertEq(f(-1, INT32_MIN), 1);

assertEq(f(-1, UINT32_MAX), 1);

assertEq(f(INT32_MAX, -1), 0);

assertEq(f(INT32_MIN, -1), 0);

assertEq(f(UINT32_MAX, -1), 1);

assertEq(f(INT32_MAX, INT32_MAX), 1);

assertEq(f(INT32_MAX, INT32_MIN), 0);

assertEq(f(UINT32_MAX, INT32_MAX), 2);

assertEq(f(INT32_MAX, UINT32_MAX), 0);

assertEq(f(UINT32_MAX, UINT32_MAX), 1);

assertEq(f(INT32_MIN, INT32_MAX), 1);

assertEq(f(INT32_MIN, UINT32_MAX), 0);

assertEq(f(INT32_MIN, INT32_MIN), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k = 0; k = (i|0)%(j|0)|0; return k|0 } return f"));

assertEq(f(4, 2), 0);

assertEq(f(3, 2), 1);

assertEq(f(3, -2), 1);

assertEq(f(-3, -2), -1);

assertEq(f(0, -1), 0);

assertEq(f(0, INT32_MAX), 0);

assertEq(f(0, INT32_MIN), 0);

assertEq(f(INT32_MAX, 0), 0);

assertEq(f(INT32_MIN, 0), 0);

assertEq(f(-1, INT32_MAX), -1);

assertEq(f(-1, INT32_MIN), -1);

assertEq(f(INT32_MAX, -1), 0);

assertEq(f(INT32_MIN, -1), 0);

assertEq(f(INT32_MAX, INT32_MAX), 0);

assertEq(f(INT32_MAX, INT32_MIN), INT32_MAX);

assertEq(f(INT32_MIN, INT32_MAX), -1);

assertEq(f(INT32_MIN, INT32_MIN), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k = 0; k = (i|0)%4|0; return k|0 } return f"));

assertEq(f(0), 0);

assertEq(f(-1), -1);

assertEq(f(-3), -3);

assertEq(f(-4), 0);

assertEq(f(INT32_MIN), 0);

assertEq(f(3), 3);

assertEq(f(4), 0);

assertEq(f(INT32_MAX), 3);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var k = 0; k = (i>>>0)%(j>>>0)|0; return k|0 } return f"));

assertEq(f(4, 2), 0);

assertEq(f(3, 2), 1);

assertEq(f(3, -2), 3);

assertEq(f(-3, -2), -3);

assertEq(f(0, -1), 0);

assertEq(f(0, INT32_MAX), 0);

assertEq(f(0, INT32_MIN), 0);

assertEq(f(0, UINT32_MAX), 0);

assertEq(f(INT32_MAX, 0), 0);

assertEq(f(INT32_MIN, 0), 0);

assertEq(f(UINT32_MAX, 0), 0);

assertEq(f(-1, INT32_MAX), 1);

assertEq(f(-1, INT32_MIN), INT32_MAX);

assertEq(f(-1, UINT32_MAX), 0);

assertEq(f(INT32_MAX, -1), INT32_MAX);

assertEq(f(INT32_MIN, -1), INT32_MIN);

assertEq(f(UINT32_MAX, -1), 0);

assertEq(f(INT32_MAX, INT32_MAX), 0);

assertEq(f(INT32_MAX, INT32_MIN), INT32_MAX);

assertEq(f(UINT32_MAX, INT32_MAX), 1);

assertEq(f(INT32_MAX, UINT32_MAX), INT32_MAX);

assertEq(f(UINT32_MAX, UINT32_MAX), 0);

assertEq(f(INT32_MIN, INT32_MAX), 1);

assertEq(f(INT32_MIN, UINT32_MAX), INT32_MIN);

assertEq(f(INT32_MIN, INT32_MIN), 0);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 / 2)|0 } return f"))(), 2);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (3 / 2)|0 } return f"))(), 1);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 % 2)|0 } return f"))(), 0);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (3 % 2)|0 } return f"))(), 1);

assertAsmTypeFail(USE_ASM + "function f() { var i=42,j=1.1; return +(i?i:j) } return f");

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return 0; 1 ? 1 : 1; return 0; } return f"))(), 0);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=42,j=1.1; return +(i?+(i|0):j) } return f"))(), 42);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=42,j=1; return (i?i:j)|0 } return f"))(), 42);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { var i=42,j=1; return 13; return (i?i:j)|0 } return f"))(), 13);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (0 > (-(~~1) >>> 0)) | 0; } return f"))(), 0);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return 0 < 4294967294 | 0; } return f"))(), 1);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; return ((i|0)>(j|0)?(i+10)|0:(j+100)|0)|0 } return f"));

assertEq(f(2, 4), 104);

assertEq(f(-2, -4), 8);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j,k) { i=i|0;j=j|0;k=k|0; return ((i|0)>(j|0) ? (i|0)>(k|0) ? i : k : (j|0)>(k|0) ? j : k)|0 } return f"));

assertEq(f(1, 2, 3), 3);

assertEq(f(1, 3, 2), 3);

assertEq(f(2, 1, 3), 3);

assertEq(f(2, 3, 1), 3);

assertEq(f(3, 1, 2), 3);

assertEq(f(3, 2, 1), 3);

var f = asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; var a=0,b=0; a=i>>>0 < 4294967292; b=(i|0) < -4; return (j ? a : b)|0 } return f"));

assertEq(f(1, true), 1);

assertEq(f(-1, true), 0);

assertEq(f(-5, true), 1);

assertEq(f(1, false), 0);

assertEq(f(-1, false), 0);

assertEq(f(-5, false), 1);

assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return (i32[0]+1)|0 } return f");

new Float64Array(BUF_64KB)[0] = 2.3;

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] + 2.0) } return f"), this, null, BUF_64KB)(), 2.3 + 2);

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] - 2.0) } return f"), this, null, BUF_64KB)(), 2.3 - 2);

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] * 2.0) } return f"), this, null, BUF_64KB)(), 2.3 * 2);

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] / 2.0) } return f"), this, null, BUF_64KB)(), 2.3 / 2);

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return +(f64[0] % 2.0) } return f"), this, null, BUF_64KB)(), 2.3 % 2);

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "function f() { return +-f64[0] } return f"), this, null, BUF_64KB)(), -2.3);

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "var sqrt=glob.Math.sqrt; function f() { return +sqrt(f64[0]) } return f"), this, null, BUF_64KB)(), Math.sqrt(2.3));

new Int32Array(BUF_64KB)[0] = 42;

assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + "var imul=glob.Math.imul; function f() { return imul(i32[0], 2)|0 } return f"), this, null, BUF_64KB)(), 84);

var f = asmLink(asmCompile(USE_ASM + "function g(i) { i=i|0; if (i) { i = ((i|0) == 2); } else { i=(i-1)|0 } return i|0; } return g "));

assertEq(f(0), -1);

assertEq(f(1), 0);

assertEq(f(2), 1);

var f = asmLink(asmCompile(USE_ASM + "function g(i) { i=i|0; if (i) { i = !i } else { i=(i-1)|0 } return i|0; } return g "));

assertEq(f(0), -1);

assertEq(f(1), 0);

assertEq(f(2), 0);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 | (2 == 2))|0 } return f"))(), 5);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { return (4 | (!2))|0 } return f"))(), 4);

var buf = new ArrayBuffer(BUF_MIN);

asmLink(asmCompile('glob', 'imp', 'buf', USE_ASM + "var i32=new glob.Int32Array(buf); var x=0; function a() { return x|0 } function b() { x=42; return 0 } function f() { i32[((b()|0) & 0x3) >> 2] = a()|0 } return f"), this, null, buf)();

assertEq(new Int32Array(buf)[0], 42);

assertEq(asmLink(asmCompile(USE_ASM + "function f() { var a=0,i=0; for (; ~~i!=4; i=(i+1)|0) { a = (a*5)|0; if (+(a>>>0) != 0.0) return 1; } return 0; } return f"))(), 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/1)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i));

    assertEq(f(Math.pow(2, i) - 1), Math.pow(2, i) - 1);

    assertEq(f(-Math.pow(2, i)), -Math.pow(2, i));

    assertEq(f(-Math.pow(2, i) - 1), -Math.pow(2, i) - 1);
}

assertEq(f(INT32_MIN), INT32_MIN);

assertEq(f(INT32_MAX), INT32_MAX);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/2)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) / 2 | 0);

    assertEq(f(Math.pow(2, i) - 1), Math.pow(2, i) - 1 / 2 | 0);

    assertEq(f(-Math.pow(2, i)), -Math.pow(2, i) / 2 | 0);

    assertEq(f(-Math.pow(2, i) - 1), -Math.pow(2, i) - 1 / 2 | 0);
}

assertEq(f(INT32_MIN), INT32_MIN / 2 | 0);

assertEq(f(INT32_MAX), INT32_MAX / 2 | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/4)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) / 4 | 0);

    assertEq(f(Math.pow(2, i) - 1), Math.pow(2, i) - 1 / 4 | 0);

    assertEq(f(-Math.pow(2, i)), -Math.pow(2, i) / 4 | 0);

    assertEq(f(-Math.pow(2, i) - 1), -Math.pow(2, i) - 1 / 4 | 0);
}

assertEq(f(INT32_MIN), INT32_MIN / 4 | 0);

assertEq(f(INT32_MAX), INT32_MAX / 4 | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((i|0)/1073741824)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) / Math.pow(2, 30) | 0);

    assertEq(f(Math.pow(2, i) - 1), Math.pow(2, i) - 1 / Math.pow(2, 30) | 0);

    assertEq(f(-Math.pow(2, i)), -Math.pow(2, i) / Math.pow(2, 30) | 0);

    assertEq(f(-Math.pow(2, i) - 1), -Math.pow(2, i) - 1 / Math.pow(2, 30) | 0);
}

assertEq(f(INT32_MIN), INT32_MIN / Math.pow(2, 30) | 0);

assertEq(f(INT32_MAX), INT32_MAX / Math.pow(2, 30) | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return ((((i|0)/1)|0)+i)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) * 2 | 0);

    assertEq(f(Math.pow(2, i) - 1), Math.pow(2, i) - 1 * 2 | 0);

    assertEq(f(-Math.pow(2, i)), -Math.pow(2, i) * 2 | 0);

    assertEq(f(-Math.pow(2, i) - 1), -Math.pow(2, i) - 1 * 2 | 0);
}

assertEq(f(INT32_MIN), INT32_MIN * 2 | 0);

assertEq(f(INT32_MAX), INT32_MAX * 2 | 0);

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/1)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i));

    assertEq(f(Math.pow(2, i + 1) - 1), Math.pow(2, i + 1) - 1);
}

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/2)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) / 2 | 0);

    assertEq(f(Math.pow(2, i + 1) - 1), Math.pow(2, i + 1) - 1 / 2 | 0);
}

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/4)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) / 4 | 0);

    assertEq(f(Math.pow(2, i + 1) - 1), Math.pow(2, i + 1) - 1 / 4 | 0);
}

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/1073741824)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) / Math.pow(2, 30) | 0);

    assertEq(f(Math.pow(2, i + 1) - 1), Math.pow(2, i + 1) - 1 / Math.pow(2, 30) | 0);
}

var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((((i|0)/1)|0)+i)|0; } return f;"));

for (let i = 0;i < 31;i++) {
    assertEq(f(Math.pow(2, i)), Math.pow(2, i) * 2 | 0);

    assertEq(f(Math.pow(2, i + 1) - 1), Math.pow(2, i + 1) - 1 * 2 | 0);
}

assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f(x, y) { x = x|0; y = y|0; g = (x>>>0)%(y>>>0)|0; return (x|0)%(y|0)|0; } return f;"))(0xff40001, 0xfff80000), 0x40001);
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap reports a new own property on a non-extensible
 * object
 */
var target = {};
Object.preventExtensions(target);

var handler = { getOwnPropertyDescriptor: () => ({}) };
for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);

vs

load(libdir + "asserts.js");

var target = ({});

Object.preventExtensions(target);

var handler = ({
    getOwnPropertyDescriptor: ()  => ({    }),
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
try {
    s.e
} catch (e) {}
o = o = s2 = /x/
for (let e in []);
x = s2
schedulegc(21)
eval("x.e=x.t")
try {
    (function() {
        this.eval("\
            (function(stdlib,fgn,heap) {\
                \"use asm\";\
                var Vie = new stdlib.Float64Array(heap);\
                var Iew = new stdlib.Int8Array(heap);\
                function f(){\
                    ent\
                }\
            })()\
        ")
    })()
} catch (e) {}

vs

try {
    s.e;
} catch (e) { 
    
}

o = o = s2 = /x/;

for (e in []) ;

x = s2;

schedulegc(21);

eval("x.e=x.t");

try {
    (function() {
        this.eval("(function(stdlib,fgn,heap) {\"use asm\";var Vie = new stdlib.Float64Array(heap);var Iew = new stdlib.Int8Array(heap);function f(){ent}})()");
    })();
} catch (e) { 
    
}
// Debugger.Frame.prototype.live is false for frames that have thrown or been thrown through

load(libdir + "asserts.js");

var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("var finalCheck;");
g.eval("(" + function () {
        var a = [];
        var dbg = Debugger(debuggeeGlobal);
        dbg.onDebuggerStatement = function (frame) {
            a.push(frame);
            for (var i = 0; i < a.length; i++)
                assertEq(a[i].live, true);
        };
        finalCheck = function (n) {
            assertEq(a.length, n);
            for (var i = 0; i < n; i++)
                assertEq(a[i].live, false);
        };
    } + ")()");

function f(n) {
    debugger;
    if (--n > 0)
        f(n);
    else
        throw "fit";
}

assertThrowsValue(function () { f(10); }, "fit");
g.finalCheck(10);

vs

load(libdir + "asserts.js");

var g = newGlobal();

g.debuggeeGlobal = this;

g.eval("var finalCheck;");

g.eval("(" + (function() {
    var a = [];
    var dbg = Debugger(debuggeeGlobal);
    dbg.onDebuggerStatement = function(frame) {
        a.push(frame);
        for (let i = 0;i < a.length;i++) assertEq(a[i].live, true);
    };
    finalCheck = function(n) {
        assertEq(a.length, n);
        for (let i = 0;i < n;i++) assertEq(a[i].live, false);
    };
}) + ")()");

function f(n) {
    debugger;;
    if (--n > 0) f(n);
 else throw "fit";

}

assertThrowsValue((function() {
    f(10);
}), "fit");

g.finalCheck(10);
// |jit-test| error: TypeError

"use strict";

setJitCompilerOption("baseline.warmup.trigger", 0);

let moduleRepo = {};
setModuleResolveHook(function(module, specifier) {
    if (specifier in moduleRepo)
        return moduleRepo[specifier];
    throw "Module '" + specifier + "' not found";
});

let mainSrc = `
import A from "A";

const a = A;

function requestAnimationFrame(f) { Promise.resolve().then(f); };

requestAnimationFrame(loopy);
a = 2;
function loopy() {
    A;
}
`;

let ASrc = `
export default 1;
`;

moduleRepo['A'] = parseModule(ASrc);

let m = parseModule(mainSrc);
m.declarationInstantiation()
m.evaluation();

vs

'use strict';

setJitCompilerOption("baseline.warmup.trigger", 0);

let moduleRepo = ({});

setModuleResolveHook((function(module, specifier) {
    if (specifier in moduleRepo) return moduleRepo[specifier];

    throw "Module '" + specifier + "' not found";
}));

let mainSrc = `
import A from "A";

const a = A;

function requestAnimationFrame(f) { Promise.resolve().then(f); };

requestAnimationFrame(loopy);
a = 2;
function loopy() {
    A;
}
`;

let ASrc = `
export default 1;
`;

moduleRepo['A'] = parseModule(ASrc);

let m = parseModule(mainSrc);

m.declarationInstantiation();

m.evaluation();
// Tests that NX disallows debuggee execution for multiple debuggers and
// multiple debuggees.

load(libdir + "asserts.js");
load(libdir + "debuggerNXHelper.js");

var g1 = newGlobal();
var g2 = newGlobal();
var dbg1 = new Debugger;
var dbg2 = new Debugger;

g1w1 = dbg1.addDebuggee(g1);

g1w2 = dbg2.addDebuggee(g1);
g2w = dbg2.addDebuggee(g2);

g1.eval(`
        function d(f) { debugger; return f; }
        function f() { return 42; }
        var o = {
          get p() { return 42; },
          set p(x) { }
        };
        `);

g2.eval(`
        function d(f) { debugger; return f; }
        function f() { return 42; }
        var o = {
          get p() { return 42; },
          set p(x) { }
        };
        `);

var strs = ["f();", "o.p", "o.p = 42"];

var fw1;
dbg1.onDebuggerStatement = (frame) => {
  fw1 = frame.arguments[0];
}
g1.eval('d(f)');
dbg1.onDebuggerStatement = undefined;
var fw2;
dbg2.onDebuggerStatement = (frame) => {
  fw2 = frame.arguments[0];
}
g2.eval('d(f)');
dbg2.onDebuggerStatement = undefined;

function testHook(hookName) {
  var newestG1Frame = dbg1.getNewestFrame();
  if (hookName != 'onNewGlobalObject' &&
      hookName != 'onNewScript' &&
      hookName != 'onNewPromise' &&
      hookName != 'onPromiseSettled')
  {
    var newestG2Frame = dbg2.getNewestFrame();
  }

  for (var s of strs) {
    // When this hook is called, g1 has been locked twice, so even invocation
    // functions do not work.
    assertEq(g1w1.executeInGlobal(s).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);
    assertEq(g1w2.executeInGlobal(s).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);
    if (newestG1Frame) {
      assertEq(newestG1Frame.eval(s).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);
    }
    assertEq(fw1.apply(null).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);

    // But g2 has only been locked once and so should work.
    assertEq(g2w.executeInGlobal(s).throw, undefined);
    if (newestG2Frame) {
      assertEq(newestG2Frame.eval(s).throw, undefined);
    }
    assertEq(fw2.apply(null).return, 42);
  }
}

testDebuggerHooksNX(dbg1, g1, () => {
  testDebuggerHooksNX(dbg2, g2, testHook);
});

vs

load(libdir + "asserts.js");

load(libdir + "debuggerNXHelper.js");

var g1 = newGlobal();

var g2 = newGlobal();

var dbg1 = new Debugger();

var dbg2 = new Debugger();

g1w1 = dbg1.addDebuggee(g1);

g1w2 = dbg2.addDebuggee(g1);

g2w = dbg2.addDebuggee(g2);

g1.eval(`
        function d(f) { debugger; return f; }
        function f() { return 42; }
        var o = {
          get p() { return 42; },
          set p(x) { }
        };
        `);

g2.eval(`
        function d(f) { debugger; return f; }
        function f() { return 42; }
        var o = {
          get p() { return 42; },
          set p(x) { }
        };
        `);

var strs = ["f();", "o.p", "o.p = 42",];

var fw1;

dbg1.onDebuggerStatement = frame => {
    fw1 = frame.arguments[0];
};

g1.eval('d(f)');

dbg1.onDebuggerStatement = undefined;

var fw2;

dbg2.onDebuggerStatement = frame => {
    fw2 = frame.arguments[0];
};

g2.eval('d(f)');

dbg2.onDebuggerStatement = undefined;

function testHook(hookName) {
    var newestG1Frame = dbg1.getNewestFrame();
    if (hookName != 'onNewGlobalObject' && hookName != 'onNewScript' && hookName != 'onNewPromise' && hookName != 'onPromiseSettled') {
        var newestG2Frame = dbg2.getNewestFrame();
    }
    for (s of strs) {
        assertEq(g1w1.executeInGlobal(s).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);

        assertEq(g1w2.executeInGlobal(s).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);

        if (newestG1Frame) {
            assertEq(newestG1Frame.eval(s).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);
        }

        assertEq(fw1.apply(null).throw.unsafeDereference() instanceof Debugger.DebuggeeWouldRun, true);

        assertEq(g2w.executeInGlobal(s).throw, undefined);

        if (newestG2Frame) {
            assertEq(newestG2Frame.eval(s).throw, undefined);
        }

        assertEq(fw2.apply(null).return, 42);
    }
}

testDebuggerHooksNX(dbg1, g1, ()  => {
    testDebuggerHooksNX(dbg2, g2, testHook);
});
function g()
{
  "use asm";
  function f()
  {
    return (0 > (0x80000000 | 0)) | 0;
  }
  return f;
}

assertEq(g()(), (0 > (0x80000000 | 0)) | 0);

vs

function g() {
    "use asm";
    function f() {
        return 0 > 0x80000000 | 0 | 0;
    }
    return f;
}

assertEq(g()(), 0 > 0x80000000 | 0 | 0);
// |jit-test| slow; skip-if: !('oomTest' in this)
"use strict";

let g = (function() {
    "use asm";
    function f() {}
    return f;
})();

oomTest(() => "" + g);

vs

'use strict';

let g = (function() {
    "use asm";
    function f() { }
    return f;
})();

oomTest(()  => "" + g);
// |jit-test| skip-if: !wasmBulkMemSupported()

// Perform a test which,
//
// * if errKind is defined, is expected to fail with an exception
//   characterised by errKind and errText.
//
// * if errKind is undefined, is expected to succeed, in which case errKind
//   and errText are ignored.
//
// The function body will be [insn1, insn2].  isMem controls whether the
// module is constructed with memory or table initializers.  haveMemOrTable
// determines whether there is actually a memory or table to work with.

function do_test(insn1, insn2, errKind, errText, isMem, haveMemOrTable)
{
    let preamble;
    if (isMem) {
        let mem_def  = haveMemOrTable ? "(memory 1 1)" : "";
        let mem_init = haveMemOrTable
                       ? `(data (i32.const 2) "\\03\\01\\04\\01")
                          (data passive "\\02\\07\\01\\08")
                          (data (i32.const 12) "\\07\\05\\02\\03\\06")
                          (data passive "\\05\\09\\02\\07\\06")`
                       : "";
        preamble
            = `;; -------- Memories --------
               ${mem_def}
               ;; -------- Memory initialisers --------
               ${mem_init}
              `;
    } else {
        let tab_def  = haveMemOrTable ? "(table 30 30 anyfunc)" : "";
        let tab_init = haveMemOrTable
                       ? `(elem (i32.const 2) 3 1 4 1)
                          (elem passive 2 7 1 8)
                          (elem (i32.const 12) 7 5 2 3 6)
                          (elem passive 5 9 2 7 6)`
                       : "";
        preamble
            = `;; -------- Tables --------
               ${tab_def}
               ;; -------- Table initialisers --------
               ${tab_init}
               ;; ------ Functions (0..9) referred by the table/esegs ------
               (func (result i32) (i32.const 0))
               (func (result i32) (i32.const 1))
               (func (result i32) (i32.const 2))
               (func (result i32) (i32.const 3))
               (func (result i32) (i32.const 4))
               (func (result i32) (i32.const 5))
               (func (result i32) (i32.const 6))
               (func (result i32) (i32.const 7))
               (func (result i32) (i32.const 8))
               (func (result i32) (i32.const 9))
              `;
    }

    let txt = "(module\n" + preamble +
              `;; -------- testfn --------
               (func (export "testfn")
                 ${insn1}
                 ${insn2}
               )
               )`;

    if (!!errKind) {
        assertErrorMessage(
            () => {
                let inst = wasmEvalText(txt);
                inst.exports.testfn();
            },
            errKind,
            errText
        );
    } else {
        let inst = wasmEvalText(txt);
        assertEq(undefined, inst.exports.testfn());
    }
}

function mem_test(insn1, insn2, errKind, errText, haveMem=true) {
    do_test(insn1, insn2, errKind, errText,
            /*isMem=*/true, haveMem);
}

function mem_test_nofail(insn1, insn2) {
    do_test(insn1, insn2, undefined, undefined,
            /*isMem=*/true, /*haveMemOrTable=*/true);
}

function tab_test(insn1, insn2, errKind, errText, haveTab=true) {
    do_test(insn1, insn2, errKind, errText,
            /*isMem=*/false, haveTab);
}

function tab_test_nofail(insn1, insn2) {
    do_test(insn1, insn2, undefined, undefined,
            /*isMem=*/false, /*haveMemOrTable=*/true);
}


//---- memory.{drop,init} -------------------------------------------------

// drop with no memory
mem_test("memory.drop 3", "",
         WebAssembly.CompileError, /can't touch memory without memory/,
         false);

// init with no memory
mem_test("(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
         WebAssembly.CompileError, /can't touch memory without memory/,
         false);

// drop with data seg ix out of range
mem_test("memory.drop 4", "",
         WebAssembly.CompileError, /memory.{drop,init} index out of range/);

// init with data seg ix out of range
mem_test("(memory.init 4 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
         WebAssembly.CompileError, /memory.{drop,init} index out of range/);

// drop with data seg ix indicating an active segment
mem_test("memory.drop 2", "",
         WebAssembly.RuntimeError, /use of invalid passive data segment/);

// init with data seg ix indicating an active segment
mem_test("(memory.init 2 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
         WebAssembly.RuntimeError, /use of invalid passive data segment/);

// init, using a data seg ix more than once is OK
mem_test_nofail(
    "(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))",
    "(memory.init 1 (i32.const 4321) (i32.const 1) (i32.const 1))");

// drop, then drop
mem_test("memory.drop 1",
         "memory.drop 1",
         WebAssembly.RuntimeError, /use of invalid passive data segment/);

// drop, then init
mem_test("memory.drop 1",
         "(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))",
         WebAssembly.RuntimeError, /use of invalid passive data segment/);

// init: seg ix is valid passive, but length to copy > len of seg
mem_test("",
         "(memory.init 1 (i32.const 1234) (i32.const 0) (i32.const 5))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, but implies copying beyond end of seg
mem_test("",
         "(memory.init 1 (i32.const 1234) (i32.const 2) (i32.const 3))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, but implies copying beyond end of dst
mem_test("",
         "(memory.init 1 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, zero len, but src offset out of bounds
mem_test("",
         "(memory.init 1 (i32.const 1234) (i32.const 4) (i32.const 0))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, zero len, but dst offset out of bounds
mem_test("",
         "(memory.init 1 (i32.const 0x10000) (i32.const 2) (i32.const 0))",
         WebAssembly.RuntimeError, /index out of bounds/);

// drop: too many args
mem_test("memory.drop 1 (i32.const 42)", "",
         WebAssembly.CompileError,
         /unused values not explicitly dropped by end of block/);

// init: too many args
mem_test("(memory.init 1 (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1))",
         "",
         SyntaxError, /parsing wasm text at/);

// init: too few args
mem_test("(memory.init 1 (i32.const 1) (i32.const 1))", "",
         WebAssembly.CompileError,
         /popping value from empty stack/);

// invalid argument types
{
    const tys  = ['i32', 'f32', 'i64', 'f64'];

    for (let ty1 of tys) {
    for (let ty2 of tys) {
    for (let ty3 of tys) {
        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
            continue;  // this is the only valid case
        let i1 = `(memory.init 1 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))`;
        mem_test(i1, "", WebAssembly.CompileError, /type mismatch/);
    }}}
}


//---- table.{drop,init} --------------------------------------------------

// drop with no table
tab_test("table.drop 3", "",
         WebAssembly.CompileError, /can't table.drop without a table/,
         false);

// init with no table
tab_test("(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", "",
         WebAssembly.CompileError, /table index out of range/,
         false);

// drop with elem seg ix out of range
tab_test("table.drop 4", "",
         WebAssembly.CompileError, /element segment index out of range for table.drop/);

// init with elem seg ix out of range
tab_test("(table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))", "",
         WebAssembly.CompileError, /table.init segment index out of range/);

// drop with elem seg ix indicating an active segment
tab_test("table.drop 2", "",
         WebAssembly.RuntimeError, /use of invalid passive element segment/);

// init with elem seg ix indicating an active segment
tab_test("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", "",
         WebAssembly.RuntimeError, /use of invalid passive element segment/);

// init, using an elem seg ix more than once is OK
tab_test_nofail(
    "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
    "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))");

// drop, then drop
tab_test("table.drop 1",
         "table.drop 1",
         WebAssembly.RuntimeError, /use of invalid passive element segment/);

// drop, then init
tab_test("table.drop 1",
         "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
         WebAssembly.RuntimeError, /use of invalid passive element segment/);

// init: seg ix is valid passive, but length to copy > len of seg
tab_test("",
         "(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, but implies copying beyond end of seg
tab_test("",
         "(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, but implies copying beyond end of dst
tab_test("",
         "(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, zero len, but src offset out of bounds
tab_test("",
         "(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))",
         WebAssembly.RuntimeError, /index out of bounds/);

// init: seg ix is valid passive, zero len, but dst offset out of bounds
tab_test("",
         "(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))",
         WebAssembly.RuntimeError, /index out of bounds/);

// drop: too many args
tab_test("table.drop 1 (i32.const 42)", "",
         WebAssembly.CompileError,
         /unused values not explicitly dropped by end of block/);

// init: too many args
tab_test("(table.init 1 (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1))",
         "",
         SyntaxError, /parsing wasm text at/);

// init: too few args
tab_test("(table.init 1 (i32.const 1) (i32.const 1))", "",
         WebAssembly.CompileError,
         /popping value from empty stack/);

// invalid argument types
{
    const tys  = ['i32', 'f32', 'i64', 'f64'];

    const ops = ['table.init 1', 'table.copy'];
    for (let ty1 of tys) {
    for (let ty2 of tys) {
    for (let ty3 of tys) {
    for (let op of ops) {
        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
            continue;  // this is the only valid case
        let i1 = `(${op} (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))`;
        tab_test(i1, "", WebAssembly.CompileError, /type mismatch/);
    }}}}
}


//---- table.copy ---------------------------------------------------------

// There are no immediates here, only 3 dynamic args.  So we're limited to
// runtime boundary checks.

// passive-segs-smoketest.js tests the normal, non-exception cases of
// table.copy.  Here we just test the boundary-failure cases.  The
// table's valid indices are 0 .. 29 inclusive.

// copy: dst range invalid
tab_test("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))",
         "",
         WebAssembly.RuntimeError, /index out of bounds/);

// copy: dst wraparound end of 32 bit offset space
tab_test("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))",
         "",
         WebAssembly.RuntimeError, /index out of bounds/);

// copy: src range invalid
tab_test("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))",
         "",
         WebAssembly.RuntimeError, /index out of bounds/);

// copy: src wraparound end of 32 bit offset space
tab_test("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))",
         "",
         WebAssembly.RuntimeError, /index out of bounds/);

// copy: zero length with both offsets in-bounds is OK
tab_test_nofail(
    "(table.copy (i32.const 15) (i32.const 25) (i32.const 0))",
    "");

// copy: zero length with dst offset out of bounds
tab_test("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))",
         "",
         WebAssembly.RuntimeError, /index out of bounds/);

// copy: zero length with src offset out of bounds
tab_test("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))",
         "",
         WebAssembly.RuntimeError, /index out of bounds/);

vs

function do_test(insn1, insn2, errKind, errText, isMem, haveMemOrTable) {
    let preamble;
    if (isMem) {
        let mem_def = haveMemOrTable ? "(memory 1 1)" : "";

        let mem_init = haveMemOrTable ? `(data (i32.const 2) "\\03\\01\\04\\01")
                          (data passive "\\02\\07\\01\\08")
                          (data (i32.const 12) "\\07\\05\\02\\03\\06")
                          (data passive "\\05\\09\\02\\07\\06")` : "";

        preamble = `;; -------- Memories --------
               ${mem_def}
               ;; -------- Memory initialisers --------
               {mem_init}
              `;
    } else {
        let tab_def = haveMemOrTable ? "(table 30 30 anyfunc)" : "";

        let tab_init = haveMemOrTable ? `(elem (i32.const 2) 3 1 4 1)
                          (elem passive 2 7 1 8)
                          (elem (i32.const 12) 7 5 2 3 6)
                          (elem passive 5 9 2 7 6)` : "";

        preamble = `;; -------- Tables --------
               ${tab_def}
               ;; -------- Table initialisers --------
               {tab_init}
               ;; ------ Functions (0..9) referred by the table/esegs ------
               (func (result i32) (i32.const 0))
               (func (result i32) (i32.const 1))
               (func (result i32) (i32.const 2))
               (func (result i32) (i32.const 3))
               (func (result i32) (i32.const 4))
               (func (result i32) (i32.const 5))
               (func (result i32) (i32.const 6))
               (func (result i32) (i32.const 7))
               (func (result i32) (i32.const 8))
               (func (result i32) (i32.const 9))
              `;
    }
    let txt = "(module\n" + preamble + `;; -------- testfn --------
               (func (export "testfn")
                 ${insn1}
                 {insn2}
               )
               )`;
    if (!!errKind) {
        assertErrorMessage(()  => {
            let inst = wasmEvalText(txt);
            inst.exports.testfn();
        }, errKind, errText);
    } else {
        let inst = wasmEvalText(txt);

        assertEq(undefined, inst.exports.testfn());
    }
}

function mem_test(insn1, insn2, errKind, errText, haveMem = true) {
    do_test(insn1, insn2, errKind, errText, true, haveMem);
}

function mem_test_nofail(insn1, insn2) {
    do_test(insn1, insn2, undefined, undefined, true, true);
}

function tab_test(insn1, insn2, errKind, errText, haveTab = true) {
    do_test(insn1, insn2, errKind, errText, false, haveTab);
}

function tab_test_nofail(insn1, insn2) {
    do_test(insn1, insn2, undefined, undefined, false, true);
}

mem_test("memory.drop 3", "", WebAssembly.CompileError, /can't touch memory without memory/, false);

mem_test("(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", "", WebAssembly.CompileError, /can't touch memory without memory/, false);

mem_test("memory.drop 4", "", WebAssembly.CompileError, /memory.{drop,init} index out of range/);

mem_test("(memory.init 4 (i32.const 1234) (i32.const 1) (i32.const 1))", "", WebAssembly.CompileError, /memory.{drop,init} index out of range/);

mem_test("memory.drop 2", "", WebAssembly.RuntimeError, /use of invalid passive data segment/);

mem_test("(memory.init 2 (i32.const 1234) (i32.const 1) (i32.const 1))", "", WebAssembly.RuntimeError, /use of invalid passive data segment/);

mem_test_nofail("(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", "(memory.init 1 (i32.const 4321) (i32.const 1) (i32.const 1))");

mem_test("memory.drop 1", "memory.drop 1", WebAssembly.RuntimeError, /use of invalid passive data segment/);

mem_test("memory.drop 1", "(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", WebAssembly.RuntimeError, /use of invalid passive data segment/);

mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 0) (i32.const 5))", WebAssembly.RuntimeError, /index out of bounds/);

mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 2) (i32.const 3))", WebAssembly.RuntimeError, /index out of bounds/);

mem_test("", "(memory.init 1 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))", WebAssembly.RuntimeError, /index out of bounds/);

mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 4) (i32.const 0))", WebAssembly.RuntimeError, /index out of bounds/);

mem_test("", "(memory.init 1 (i32.const 0x10000) (i32.const 2) (i32.const 0))", WebAssembly.RuntimeError, /index out of bounds/);

mem_test("memory.drop 1 (i32.const 42)", "", WebAssembly.CompileError, /unused values not explicitly dropped by end of block/);

mem_test("(memory.init 1 (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1))", "", SyntaxError, /parsing wasm text at/);

mem_test("(memory.init 1 (i32.const 1) (i32.const 1))", "", WebAssembly.CompileError, /popping value from empty stack/);

{
    const tys = ['i32', 'f32', 'i64', 'f64',];

    for (ty1 of tys) {
        for (ty2 of tys) {
            for (ty3 of tys) {
                if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') continue;


                let i1 = `(memory.init 1 (${ty1}.const 1) ({ty2}.const 1) ({ty3}.const 1))`;

                mem_test(i1, "", WebAssembly.CompileError, /type mismatch/);
            }
        }
    }
}
tab_test("table.drop 3", "", WebAssembly.CompileError, /can't table.drop without a table/, false);

tab_test("(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", "", WebAssembly.CompileError, /table index out of range/, false);

tab_test("table.drop 4", "", WebAssembly.CompileError, /element segment index out of range for table.drop/);

tab_test("(table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))", "", WebAssembly.CompileError, /table.init segment index out of range/);

tab_test("table.drop 2", "", WebAssembly.RuntimeError, /use of invalid passive element segment/);

tab_test("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", "", WebAssembly.RuntimeError, /use of invalid passive element segment/);

tab_test_nofail("(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))");

tab_test("table.drop 1", "table.drop 1", WebAssembly.RuntimeError, /use of invalid passive element segment/);

tab_test("table.drop 1", "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", WebAssembly.RuntimeError, /use of invalid passive element segment/);

tab_test("", "(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("", "(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("", "(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("", "(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("", "(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("table.drop 1 (i32.const 42)", "", WebAssembly.CompileError, /unused values not explicitly dropped by end of block/);

tab_test("(table.init 1 (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1))", "", SyntaxError, /parsing wasm text at/);

tab_test("(table.init 1 (i32.const 1) (i32.const 1))", "", WebAssembly.CompileError, /popping value from empty stack/);

{
    const tys = ['i32', 'f32', 'i64', 'f64',];

    const ops = ['table.init 1', 'table.copy',];

    for (ty1 of tys) {
        for (ty2 of tys) {
            for (ty3 of tys) {
                for (op of ops) {
                    if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') continue;


                    let i1 = `(${op} ({ty1}.const 1) ({ty2}.const 1) ({ty3}.const 1))`;

                    tab_test(i1, "", WebAssembly.CompileError, /type mismatch/);
                }
            }
        }
    }
}
tab_test("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))", "", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))", "", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))", "", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))", "", WebAssembly.RuntimeError, /index out of bounds/);

tab_test_nofail("(table.copy (i32.const 15) (i32.const 25) (i32.const 0))", "");

tab_test("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", "", WebAssembly.RuntimeError, /index out of bounds/);

tab_test("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", "", WebAssembly.RuntimeError, /index out of bounds/);
// Tests that invocation functions work outside of Debugger code.

load(libdir + "asserts.js");

var g = newGlobal();
var dbg = new Debugger();
var gw = dbg.addDebuggee(g);

g.eval(`
       function f() { debugger; return 42; }
       function f2() { return 42; }
       var o = {
         get p() { return 42; },
         set p(x) { }
       };
       `);

var strs = ["f(f2);", "o.p", "o.p = 42"];

var f2w;
dbg.onDebuggerStatement = (frame) => {
  f2w = frame.arguments[0];
};

for (var s of strs) {
  assertEq(gw.executeInGlobal(s).return, 42);
}
assertEq(f2w.apply(null).return, 42);

vs

load(libdir + "asserts.js");

var g = newGlobal();

var dbg = new Debugger();

var gw = dbg.addDebuggee(g);

g.eval(`
       function f() { debugger; return 42; }
       function f2() { return 42; }
       var o = {
         get p() { return 42; },
         set p(x) { }
       };
       `);

var strs = ["f(f2);", "o.p", "o.p = 42",];

var f2w;

dbg.onDebuggerStatement = frame => {
    f2w = frame.arguments[0];
};

for (s of strs) {
    assertEq(gw.executeInGlobal(s).return, 42);
}

assertEq(f2w.apply(null).return, 42);
var sandbox = evalcx("lazy");

// Ensure we can't change the "lazy" property of the sandbox to an accessor,
// because that'd allow to execute arbitrary side-effects when calling the
// resolve hook of the sandbox.
var err;
try {
    Object.defineProperty(sandbox, "lazy", {
        get() {
            Object.defineProperty(sandbox, "foo", { value: 0 });
        }
    });
} catch (e) {
    err = e;
}
assertEq(err instanceof TypeError, true);

// Don't assert here.
sandbox.foo = 1;

vs

var sandbox = evalcx("lazy");

var err;

try {
    Object.defineProperty(sandbox, "lazy", ({
        get: (function() {
            Object.defineProperty(sandbox, "foo", {
                value: 0,
            });
        }),
    }));
} catch (e) {
    err = e;
}

assertEq(err instanceof TypeError, true);

sandbox.foo = 1;
// The receiver argument is passed through proxies with no "set" handler.

var hits;
var a = new Proxy({}, {
    set(t, id, value, receiver) {
        assertEq(id, "prop");
        assertEq(value, 3);
        assertEq(receiver, b);
        hits++;
    }
});
var b = new Proxy(a, {});
hits = 0;
b.prop = 3;
assertEq(hits, 1);

vs

var hits;

var a = new Proxy(({}), ({
    set: (function(t, id, value, receiver) {
        assertEq(id, "prop");
        assertEq(value, 3);
        assertEq(receiver, b);
        hits++;
    }),
}));

var b = new Proxy(a, ({}));

hits = 0;

b.prop = 3;

assertEq(hits, 1);
var e = new Error();
function test() {
  var arr = new Float32Array(1);
  for (var Number in e) {}
  var a = arr [0];
  switch (a) {}
} test();

vs

var e = new Error();

function test() {
    var arr = new Float32Array(1);
    for (Number in e) { 
        
    }
    var a = arr[0];
    switch (a) {    }
}

test();
gczeal(4);
var symbols = [Symbol(), Symbol("comet"), Symbol.for("moon"), Symbol.iterator, 0];
for (var a of symbols) {}

vs

gczeal(4);

var symbols = [Symbol(), Symbol("comet"), Symbol.for("moon"), Symbol.iterator, 0,];

for (a of symbols) { 
    
}
function* gen() {
    try {
	yield 3;
    } finally {
	quit();
    }
}
try {
    for (var i of gen())
	foo();
} catch (e) {}

vs

function *gen() {
    try {
        yield 3;
    } finally {
        quit();
    }
}

try {
    for (i of gen()) foo();
} catch (e) { 
    
}
// Point-testing various optimizations in the wasm baseline compiler.

// Boolean optimization for control (bug 1286816).
//
// These optimizations combine a test (a comparison or Eqz) with an
// immediately following conditional branch (BrIf, If, and Select), to
// avoid generating a boolean value that is then tested with a
// compare-to-zero.
//
// On AngryBots as of November 2016, 84% of all test instructions
// (measured statically) are optimized by this method.

function testEqzBrIf(value, type, untaken, taken, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (set_local 0 (${type}.const ${value}))
			    (set_local 1 (i32.const ${taken}))
			    (block $b
			     (br_if $b (${type}.eqz (get_local 0)))
			     (set_local 1 (i32.const ${untaken})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64"].forEach(t => testEqzBrIf(0, t, 37, 42, 42)); // Taken
["i32", "i64"].forEach(t => testEqzBrIf(1, t, 37, 42, 37)); // Untaken

function testCmpBrIf(value, type, untaken, taken, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (set_local 1 (i32.const ${taken}))
			    (block $b
			     (br_if $b (${type}.eq (get_local 0) (${type}.const ${value})))
			     (set_local 1 (i32.const ${untaken})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64", "f32", "f64"].forEach(t => testCmpBrIf(0, t, 37, 42, 42)); // Branch taken
["i32", "i64", "f32", "f64"].forEach(t => testCmpBrIf(1, t, 37, 42, 37)); // Branch untaken

function testEqzSelect(value, type, iftrue, iffalse, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (set_local 0 (${type}.const ${value}))
			    (select (i32.const ${iftrue})
			            (i32.const ${iffalse})
			            (${type}.eqz (get_local 0))))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64"].forEach(t => testEqzSelect(0, t, 42, 37, 42)); // Select first
["i32", "i64"].forEach(t => testEqzSelect(1, t, 42, 37, 37)); // Select second

function testCmpSelect(value, type, iftrue, iffalse, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (select (i32.const ${iftrue})
			            (i32.const ${iffalse})
			            (${type}.eq (get_local 0) (${type}.const ${value}))))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64", "f32", "f64"].forEach(t => testCmpSelect(0, t, 42, 37, 42)); // Select first
["i32", "i64", "f32", "f64"].forEach(t => testCmpSelect(1, t, 42, 37, 37)); // Select second

function testEqzIf(value, type, trueBranch, falseBranch, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (set_local 0 (${type}.const ${value}))
			    (if (${type}.eqz (get_local 0))
				(set_local 1 (i32.const ${trueBranch}))
			        (set_local 1 (i32.const ${falseBranch})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64"].forEach(t => testEqzIf(0, t, 42, 37, 42)); // Taken
["i32", "i64"].forEach(t => testEqzIf(1, t, 42, 37, 37)); // Untaken

function testCmpIf(value, type, trueBranch, falseBranch, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (if (${type}.eq (get_local 0) (${type}.const ${value}))
				(set_local 1 (i32.const ${trueBranch}))
			        (set_local 1 (i32.const ${falseBranch})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64", "f32", "f64"].forEach(t => testCmpIf(0, t, 42, 37, 42)); // Taken
["i32", "i64", "f32", "f64"].forEach(t => testCmpIf(1, t, 42, 37, 37)); // Untaken

vs

function testEqzBrIf(value, type, untaken, taken, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (set_local 0 ({type}.const {value}))
			    (set_local 1 (i32.const {taken}))
			    (block $b
			     (br_if $b ({type}.eqz (get_local 0)))
			     (set_local 1 (i32.const {untaken})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64",].forEach(t => testEqzBrIf(0, t, 37, 42, 42));

["i32", "i64",].forEach(t => testEqzBrIf(1, t, 37, 42, 37));

function testCmpBrIf(value, type, untaken, taken, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (set_local 1 (i32.const {taken}))
			    (block $b
			     (br_if $b ({type}.eq (get_local 0) ({type}.const {value})))
			     (set_local 1 (i32.const {untaken})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64", "f32", "f64",].forEach(t => testCmpBrIf(0, t, 37, 42, 42));

["i32", "i64", "f32", "f64",].forEach(t => testCmpBrIf(1, t, 37, 42, 37));

function testEqzSelect(value, type, iftrue, iffalse, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (set_local 0 ({type}.const {value}))
			    (select (i32.const {iftrue})
			            (i32.const {iffalse})
			            ({type}.eqz (get_local 0))))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64",].forEach(t => testEqzSelect(0, t, 42, 37, 42));

["i32", "i64",].forEach(t => testEqzSelect(1, t, 42, 37, 37));

function testCmpSelect(value, type, iftrue, iffalse, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (select (i32.const {iftrue})
			            (i32.const {iffalse})
			            ({type}.eq (get_local 0) ({type}.const {value}))))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64", "f32", "f64",].forEach(t => testCmpSelect(0, t, 42, 37, 42));

["i32", "i64", "f32", "f64",].forEach(t => testCmpSelect(1, t, 42, 37, 37));

function testEqzIf(value, type, trueBranch, falseBranch, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (set_local 0 ({type}.const {value}))
			    (if ({type}.eqz (get_local 0))
				(set_local 1 (i32.const {trueBranch}))
			        (set_local 1 (i32.const {falseBranch})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64",].forEach(t => testEqzIf(0, t, 42, 37, 42));

["i32", "i64",].forEach(t => testEqzIf(1, t, 42, 37, 37));

function testCmpIf(value, type, trueBranch, falseBranch, expected) {
    var f = wasmEvalText(`(module
			   (func (result i32)
			    (local ${type})
			    (local i32)
			    (if ({type}.eq (get_local 0) ({type}.const {value}))
				(set_local 1 (i32.const {trueBranch}))
			        (set_local 1 (i32.const {falseBranch})))
			    (get_local 1))
			   (export "f" 0))`).exports["f"];
    assertEq(f(), expected);
}

["i32", "i64", "f32", "f64",].forEach(t => testCmpIf(0, t, 42, 37, 42));

["i32", "i64", "f32", "f64",].forEach(t => testCmpIf(1, t, 42, 37, 37));
// |jit-test| error:TypeError
// stdlib is undefined

(function(stdlib, n, heap) {
    "use asm"
    var Int16ArrayView = new stdlib.Int16Array(heap)
    function f() {
        var x = 4.
        Int16ArrayView[~~((1 ? .0 : .9) % x) >> 1] = 0
        u(x)
    }
})()

vs

(function(stdlib, n, heap) {
    "use asm";
    var Int16ArrayView = new stdlib.Int16Array(heap);
    function f() {
        var x = 4.;
        Int16ArrayView[~~1 ? .0 : .9 % x >> 1] = 0;
        u(x);
    }
})();
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap returns a non-configurable descriptor for a
 * non-existent property
 */
var handler = { getOwnPropertyDescriptor: () => ({ configurable: false }) };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    getOwnPropertyDescriptor: ()  => ({
        configurable: false,
    }),
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
DoWhile( new DoWhileObject( false, true, true, true ) );
function DoWhileObject( out1, out2, out3, in1 ) {}
function DoWhile( object ) {
    if ( object.breakOutOne ) {}
  innie:
    do {
	if ( object.breakOutThree ) {}
    } while ( false );
}

vs

DoWhile(new DoWhileObject(false, true, true, true));

function DoWhileObject(out1, out2, out3, in1) { }

function DoWhile(object) {
    if (object.breakOutOne) { 
        
    }
    innie: do {
        if (object.breakOutThree) { 
            
        }
    } while (false);

    ;
}
// Binary: cache/js-dbg-64-1fd6c40d3852-linux
// Flags: --ion-eager
//
function TestCase(n, d, e, a) {}
var msPerDay =   86400000;
var msPerHour =   3600000;
var now = new Date();
var TIME_NOW = now.valueOf();
function DaysInYear( y ) {
  if ( y % 4 != 0 ) {
    return 365;
  }
    return 366;
}
function TimeInYear( y ) {
  return ( DaysInYear(y) * msPerDay );
}
function TimeFromYear( y ) {
  return ( msPerDay * DayFromYear(y) );
}
function DayFromYear( y ) {
  return ( 365*(y-1970) +
           Math.floor((y-1601)/400) );
}
function InLeapYear( t ) {
  if ( DaysInYear(YearFromTime(t)) == 365 ) {
    return 0;
  }
  if ( DaysInYear(YearFromTime(t)) == 366 ) {
  }
}
function YearFromTime( t ) {
  var sign = ( t < 0 ) ? -1 : 1;
  var year = ( sign < 0 ) ? 1969 : 1970;
  for ( var timeToTimeZero = t; ;  ) {
    timeToTimeZero -= sign * TimeInYear(year)
      if ( sign < 0 ) {
      } else {
        if ( sign * timeToTimeZero < 0 ) {
          break;
        } else {
          year += sign;
        }
      }
  }
  return ( year );
}
function WeekDay( t ) {}
function LocalTZA() {}
function LocalTime( t ) {
  var dst_start = GetDSTStart(t);
}
function GetFirstSundayInMonth( t, m ) {
  var leap = InLeapYear(t);
}
function GetDSTStart( t ) {
  return (GetFirstSundayInMonth(t, 2) + 7*msPerDay + 2*msPerHour - LocalTZA());
}
var SECTION = "15.9.5.12";
addTestCase( TIME_NOW );
function addTestCase( t ) {
  var start = TimeFromYear(YearFromTime(t));
  var stop  = TimeFromYear(YearFromTime(t) + 1);
  for (var d = start; d < stop; d += msPerDay) {
    new TestCase( SECTION,
                  WeekDay((LocalTime(d))),
                  (__lookupGetter__) );
  }
}

vs

function TestCase(n, d, e, a) { }

var msPerDay = 86400000;

var msPerHour = 3600000;

var now = new Date();

var TIME_NOW = now.valueOf();

function DaysInYear(y) {
    if (y % 4 != 0) {
        return 365;
    }
    return 366;
}

function TimeInYear(y) {
    return DaysInYear(y) * msPerDay;
}

function TimeFromYear(y) {
    return msPerDay * DayFromYear(y);
}

function DayFromYear(y) {
    return 365 * y - 1970 + Math.floor(y - 1601 / 400);
}

function InLeapYear(t) {
    if (DaysInYear(YearFromTime(t)) == 365) {
        return 0;
    }
    if (DaysInYear(YearFromTime(t)) == 366) { 
        
    }
}

function YearFromTime(t) {
    var sign = t < 0 ? -1 : 1;
    var year = sign < 0 ? 1969 : 1970;
    for (let timeToTimeZero = t;;) {
        timeToTimeZero -= sign * TimeInYear(year);

        if (sign < 0) { 
            
        } else {
            if (sign * timeToTimeZero < 0) {
                break;
            } else {
                year += sign;
            }
        }
    }
    return year;
}

function WeekDay(t) { }

function LocalTZA() { }

function LocalTime(t) {
    var dst_start = GetDSTStart(t);
}

function GetFirstSundayInMonth(t, m) {
    var leap = InLeapYear(t);
}

function GetDSTStart(t) {
    return GetFirstSundayInMonth(t, 2) + 7 * msPerDay + 2 * msPerHour - LocalTZA();
}

var SECTION = "15.9.5.12";

addTestCase(TIME_NOW);

function addTestCase(t) {
    var start = TimeFromYear(YearFromTime(t));
    var stop = TimeFromYear(YearFromTime(t) + 1);
    for (let d = start;d < stop;d += msPerDay) {
        new TestCase(SECTION, WeekDay(LocalTime(d)), __lookupGetter__);
    }
}
load(libdir + "asserts.js");

// Throw TypeError if trap returns a property key multiple times.

var handler = { ownKeys: () => [ 'foo', 'foo' ] };
for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
    assertThrowsInstanceOf(() => Object.keys(p), TypeError);

vs

load(libdir + "asserts.js");

var handler = ({
    ownKeys: ()  => ['foo', 'foo',],
});

for (p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy,]) assertThrowsInstanceOf(()  => Object.keys(p), TypeError);
// Stepping works across `yield` in generators.

// Set up debuggee.
var g = newGlobal();
g.log = "";
g.eval(`
function* range(stop) {               // line 2
    for (let i = 0; i < stop; i++) {  // 3
        yield i;                      // 4
        log += " ";                   // 5
    }                                 // 6
    log += "^";                       // 7
}
`);

// Set up debugger.
let previousLine = -1;
let dbg = new Debugger(g);
dbg.onEnterFrame = frame => {
    frame.onStep = function () {
        assertEq(this, frame);
        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
        if (previousLine != line) {
            g.log += line; // We stepped to a new line.
            previousLine = line;
        }
    };
    dbg.onEnterFrame = undefined;
};

// Run.
for (let value of g.range(3)) {
    g.log += "*";
}

assertEq(g.log, "234*5 34*5 34*5 37^");

vs

var g = newGlobal();

g.log = "";

g.eval(`
function* range(stop) {               // line 2
    for (let i = 0; i < stop; i++) {  // 3
        yield i;                      // 4
        log += " ";                   // 5
    }                                 // 6
    log += "^";                       // 7
}
`);

let previousLine = -1;

let dbg = new Debugger(g);

dbg.onEnterFrame = frame => {
    frame.onStep = function() {
        assertEq(this, frame);
        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
        if (previousLine != line) {
            g.log += line;

            previousLine = line;
        }
    };
    dbg.onEnterFrame = undefined;
};

for (value of g.range(3)) {
    g.log += "*";
}

assertEq(g.log, "234*5 34*5 34*5 37^");
// |jit-test| skip-if: helperThreadCount() === 0

// Test multiple concurrent off-thread parse jobs.

function assertFails(f) {
    let failed = false;
    try {
        f();
    } catch (e) {
        failed = true;
    }
    assertEq(failed, true);
}

function encodeScript(source)
{
    let entry = cacheEntry(source);
    let global = newGlobal({ cloneSingletons: true });
    evaluate(entry, { global: global, saveBytecode: true });
    return entry;
}

let a, b, c;

// Calling run functions without arguments assumes a single off-thread job.

// Test run functions fail when no jobs exist.

assertFails(() => runOffThreadScript());

assertFails(() => finishOffThreadModule());

assertFails(() => runOffThreadDecodedScript());

// Test run functions fail when multiple jobs exist and no ID specified.

a = offThreadCompileScript("");
b = offThreadCompileScript("");
assertFails(() => runOffThreadScript());
runOffThreadScript(a);
runOffThreadScript(b);

a = offThreadCompileModule("");
b = offThreadCompileModule("");
assertFails(() => finishOffThreadModule());
finishOffThreadModule(a);
finishOffThreadModule(b);

a = offThreadDecodeScript(encodeScript(""));
b = offThreadDecodeScript(encodeScript(""));
assertFails(() => runOffThreadScript());
runOffThreadDecodedScript(a);
runOffThreadDecodedScript(b);

// Test fun functions succeed when a single job exist and no ID specified.

offThreadCompileScript("42");
assertEq(runOffThreadScript(), 42);

offThreadCompileModule("");
assertEq(typeof finishOffThreadModule(), "object");

offThreadDecodeScript(encodeScript("23"));
assertEq(runOffThreadDecodedScript(), 23);

// Run functions take an ID argument returned from the compile function.

// Test bad ID type and unknown ID.

offThreadCompileScript("");
assertFails(() => runOffThreadScript("foo"));
assertFails(() => runOffThreadScript(42));
runOffThreadScript();

offThreadCompileModule("");
assertFails(() => finishOffThreadModule("foo"));
assertFails(() => finishOffThreadModule(42));
finishOffThreadModule();

offThreadDecodeScript(encodeScript(""));
assertFails(() => runOffThreadDecodedScript("foo"));
assertFails(() => runOffThreadDecodedScript(42));
runOffThreadDecodedScript();

// Test stale ID.

a = offThreadCompileScript("");
runOffThreadScript(a);
assertFails(() => runOffThreadScript(a));

a = offThreadCompileModule("");
finishOffThreadModule(a);
assertFails(() => finishOffThreadModule(a));

a = offThreadDecodeScript(encodeScript(""));
runOffThreadDecodedScript(a);
assertFails(() => runOffThreadDecodedScript(a));

// Test wrong job kind.

a = offThreadCompileScript("");
b = offThreadCompileModule("");
c = offThreadDecodeScript(encodeScript(""));
assertFails(() => runOffThreadScript(b));
assertFails(() => runOffThreadScript(c));
assertFails(() => finishOffThreadModule(a));
assertFails(() => finishOffThreadModule(c));
assertFails(() => runOffThreadDecodedScript(a));
assertFails(() => runOffThreadDecodedScript(b));
runOffThreadScript(a);
finishOffThreadModule(b);
runOffThreadDecodedScript(c);

// Test running multiple jobs.

a = offThreadCompileScript("1");
b = offThreadCompileScript("2");
assertEq(runOffThreadScript(a), 1);
assertEq(runOffThreadScript(b), 2);

a = offThreadCompileModule("");
b = offThreadCompileModule("");
assertEq(typeof finishOffThreadModule(a), "object");
assertEq(typeof finishOffThreadModule(b), "object");

a = offThreadDecodeScript(encodeScript("3"));
b = offThreadDecodeScript(encodeScript("4"));
assertEq(runOffThreadDecodedScript(a), 3);
assertEq(runOffThreadDecodedScript(b), 4);

// Test many jobs.

const count = 100;
let jobs;

jobs = new Array(count);
for (let i = 0; i < jobs.length; i++)
    jobs[i] = offThreadCompileScript(`${i} * ${i}`);
for (let i = 0; i < jobs.length; i++)
    assertEq(runOffThreadScript(jobs[i]), i * i);

jobs = new Array(count);
for (let i = 0; i < jobs.length; i++)
    jobs[i] = offThreadCompileModule("");
for (let i = 0; i < jobs.length; i++)
    assertEq(typeof finishOffThreadModule(jobs[i]), "object");

jobs = new Array(count);
for (let i = 0; i < jobs.length; i++)
    jobs[i] = offThreadDecodeScript(encodeScript(`${i} * ${i}`));
for (let i = 0; i < jobs.length; i++)
    assertEq(runOffThreadDecodedScript(jobs[i]), i * i);

vs

function assertFails(f) {
    let failed = false;
    try {
        f();
    } catch (e) {
        failed = true;
    }
    assertEq(failed, true);
}

function encodeScript(source) {
    let entry = cacheEntry(source);
    let global = newGlobal({
        cloneSingletons: true,
    });
    evaluate(entry, {
        global: global,
        saveBytecode: true,
    });
    return entry;
}

let a, b, c;

assertFails(()  => runOffThreadScript());

assertFails(()  => finishOffThreadModule());

assertFails(()  => runOffThreadDecodedScript());

a = offThreadCompileScript("");

b = offThreadCompileScript("");

assertFails(()  => runOffThreadScript());

runOffThreadScript(a);

runOffThreadScript(b);

a = offThreadCompileModule("");

b = offThreadCompileModule("");

assertFails(()  => finishOffThreadModule());

finishOffThreadModule(a);

finishOffThreadModule(b);

a = offThreadDecodeScript(encodeScript(""));

b = offThreadDecodeScript(encodeScript(""));

assertFails(()  => runOffThreadScript());

runOffThreadDecodedScript(a);

runOffThreadDecodedScript(b);

offThreadCompileScript("42");

assertEq(runOffThreadScript(), 42);

offThreadCompileModule("");

assertEq(typeof finishOffThreadModule(), "object");

offThreadDecodeScript(encodeScript("23"));

assertEq(runOffThreadDecodedScript(), 23);

offThreadCompileScript("");

assertFails(()  => runOffThreadScript("foo"));

assertFails(()  => runOffThreadScript(42));

runOffThreadScript();

offThreadCompileModule("");

assertFails(()  => finishOffThreadModule("foo"));

assertFails(()  => finishOffThreadModule(42));

finishOffThreadModule();

offThreadDecodeScript(encodeScript(""));

assertFails(()  => runOffThreadDecodedScript("foo"));

assertFails(()  => runOffThreadDecodedScript(42));

runOffThreadDecodedScript();

a = offThreadCompileScript("");

runOffThreadScript(a);

assertFails(()  => runOffThreadScript(a));

a = offThreadCompileModule("");

finishOffThreadModule(a);

assertFails(()  => finishOffThreadModule(a));

a = offThreadDecodeScript(encodeScript(""));

runOffThreadDecodedScript(a);

assertFails(()  => runOffThreadDecodedScript(a));

a = offThreadCompileScript("");

b = offThreadCompileModule("");

c = offThreadDecodeScript(encodeScript(""));

assertFails(()  => runOffThreadScript(b));

assertFails(()  => runOffThreadScript(c));

assertFails(()  => finishOffThreadModule(a));

assertFails(()  => finishOffThreadModule(c));

assertFails(()  => runOffThreadDecodedScript(a));

assertFails(()  => runOffThreadDecodedScript(b));

runOffThreadScript(a);

finishOffThreadModule(b);

runOffThreadDecodedScript(c);

a = offThreadCompileScript("1");

b = offThreadCompileScript("2");

assertEq(runOffThreadScript(a), 1);

assertEq(runOffThreadScript(b), 2);

a = offThreadCompileModule("");

b = offThreadCompileModule("");

assertEq(typeof finishOffThreadModule(a), "object");

assertEq(typeof finishOffThreadModule(b), "object");

a = offThreadDecodeScript(encodeScript("3"));

b = offThreadDecodeScript(encodeScript("4"));

assertEq(runOffThreadDecodedScript(a), 3);

assertEq(runOffThreadDecodedScript(b), 4);

const count = 100;

let jobs;

jobs = new Array(count);

for (let i = 0;i < jobs.length;i++) jobs[i] = offThreadCompileScript(`${i} * {i}`);

for (let i = 0;i < jobs.length;i++) assertEq(runOffThreadScript(jobs[i]), i * i);

jobs = new Array(count);

for (let i = 0;i < jobs.length;i++) jobs[i] = offThreadCompileModule("");

for (let i = 0;i < jobs.length;i++) assertEq(typeof finishOffThreadModule(jobs[i]), "object");

jobs = new Array(count);

for (let i = 0;i < jobs.length;i++) jobs[i] = offThreadDecodeScript(encodeScript(`${i} * {i}`));

for (let i = 0;i < jobs.length;i++) assertEq(runOffThreadDecodedScript(jobs[i]), i * i);
// 'let' after "use strict" directive without semicolon is lexed as TOK_NAME
// before parsing the directive.  'let' with TOK_NAME should be handled
// correctly in strict mode.

"use strict"
let a = 1;

vs

'use strict';

let a = 1;
load(libdir + "asserts.js");

/*
 * Throw a TypeError if the trap defines a new property on a non-extensible
 * object
 */
var target = {};
Object.preventExtensions(target);

var handler = { defineProperty: function (target, name, desc) { return true; } };

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    assertThrowsInstanceOf(function () {
        Object.defineProperty(p, 'foo', { configurable: true });
    }, TypeError);
}

vs

load(libdir + "asserts.js");

var target = ({});

Object.preventExtensions(target);

var handler = ({
    defineProperty: (function(target, name, desc) {
        return true;
    }),
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    assertThrowsInstanceOf(function() {
        Object.defineProperty(p, 'foo', {
            configurable: true,
        });
    }, TypeError);
}
// set.iterator() is live: entries added during iteration are visited.

var set = new Set([5]);
var log = '';
for (let x of set) {
    log += x + ';';
    if (x > 0)
        set.add(x - 1);
}
assertEq(log, '5;4;3;2;1;0;');
assertEq(set.size, 6);

vs

var set = new Set([5,]);

var log = '';

for (x of set) {
    log += x + ';';

    if (x > 0) set.add(x - 1);

}

assertEq(log, '5;4;3;2;1;0;');

assertEq(set.size, 6);
gczeal(2);
g = newGlobal();
dbg = Debugger(g);
function loop() {
  for (var i = 0; i < 10; i++)
    debugger;
}
g.eval(loop.toSource());
dbg.onDebuggerStatement = function(f) {
  f.script.getOffsetsCoverage();
}
dbg.collectCoverageInfo = true;
g.eval("loop")();

vs

gczeal(2);

g = newGlobal();

dbg = Debugger(g);

function loop() {
    for (let i = 0;i < 10;i++) debugger;;
}

g.eval(loop.toSource());

dbg.onDebuggerStatement = (function(f) {
    f.script.getOffsetsCoverage();
});

dbg.collectCoverageInfo = true;

g.eval("loop")();
// overflows occurring during constant folding

var y = -null - y;
assertEq(y, NaN);

var x = -(void 0);
assertEq(x, NaN);

function overdiv() {
  for(var i=0; i<25; i++) {
    var a, b;
    function f() { 
    }
    a = f();
    b = (123 ^ 1) / 1234;
  }
}
overdiv();

function overadd() {
  var a = 0x7ffffff0;
  var b = 100;
  return a + b;
}
overadd();

vs

var y = -null - y;

assertEq(y, NaN);

var x = -void 0;

assertEq(x, NaN);

function overdiv() {
    for (let i = 0;i < 25;i++) {
        var a, b;

        function f() { }

        a = f();

        b = 123 ^ 1 / 1234;
    }
}

overdiv();

function overadd() {
    var a = 0x7ffffff0;
    var b = 100;
    return a + b;
}

overadd();
load(libdir + "asserts.js");

// Allow [[GetOwnPropertyDescriptor]] to spoof enumerability of target object's
// properties. Note that this also tests that the getOwnPropertyDescriptor is
// called by Object.keys(), as expected.

var target = {};
var handler = {
    getOwnPropertyDescriptor : function (target, P) {
        var targetDesc = Object.getOwnPropertyDescriptor(target, P);
        // Lie about enumerability
        targetDesc.enumerable = !targetDesc.enumerable;
        return targetDesc;
    }
};

for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
    Object.defineProperty(target, "foo", { configurable: true, enumerable: false });
    assertDeepEq(Object.keys(p), ["foo"]);

    Object.defineProperty(target, "foo", {configurable: true, enumerable: true});
    assertDeepEq(Object.keys(p), []);
}

vs

load(libdir + "asserts.js");

var target = ({});

var handler = ({
    getOwnPropertyDescriptor: (function(target, P) {
        var targetDesc = Object.getOwnPropertyDescriptor(target, P);
        targetDesc.enumerable = !targetDesc.enumerable;
        return targetDesc;
    }),
});

for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy,]) {
    Object.defineProperty(target, "foo", {
        configurable: true,
        enumerable: false,
    });

    assertDeepEq(Object.keys(p), ["foo",]);

    Object.defineProperty(target, "foo", {
        configurable: true,
        enumerable: true,
    });

    assertDeepEq(Object.keys(p), []);
}
/*
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/licenses/publicdomain/
 */

setJitCompilerOption("ion.warmup.trigger", 30);

var Vec3u32Type = TypedObject.uint32.array(3);

function foo_u32() {
  for (var i = 0; i < 5000; i += 10) {
    var vec = new Vec3u32Type();
    // making index non-trivially dependent on |i| to foil compiler optimization
    vec[(i)     % 3] = i;
    vec[(i + 1) % 3] = i+1;
    vec[(i + 2) % 3] = i+2;
    var sum = vec[0] + vec[1] + vec[2];
    assertEq(sum, 3*i + 3);
  }
}

foo_u32();

vs

setJitCompilerOption("ion.warmup.trigger", 30);

var Vec3u32Type = TypedObject.uint32.array(3);

function foo_u32() {
    for (let i = 0;i < 5000;i += 10) {
        var vec = new Vec3u32Type();

        vec[i % 3] = i;

        vec[i + 1 % 3] = i + 1;

        vec[i + 2 % 3] = i + 2;

        var sum = vec[0] + vec[1] + vec[2];

        assertEq(sum, 3 * i + 3);
    }
}

foo_u32();
let proxy = new Proxy({
    a: 1,
    b: 2,
    c: 3
}, {
    enumerate() {
        // Should not be invoked.
        assertEq(false, true);
    },

    ownKeys() {
        return ['a', 'b'];
    }
});

let object = Object.create(proxy);
object.d = 4;

let a = [];
for (let x in object) {
  a.push(x);
}
assertEq(a.toString(), "d,a,b");

vs

let proxy = new Proxy(({
    a: 1,
    b: 2,
    c: 3,
}), ({
    enumerate: (function() {
        assertEq(false, true);
    }),
    ownKeys: (function() {
        return ['a', 'b',];
    }),
}));

let object = Object.create(proxy);

object.d = 4;

let a = [];

for (x in object) {
    a.push(x);
}

assertEq(a.toString(), "d,a,b");
// |jit-test| skip-if: !isAsmJSCompilationAvailable()
load(libdir + "asm.js");
load(libdir + "asserts.js");

// This test runs a lot of code and is very slow with --ion-eager. Use a minimum
// Ion warmup trigger of 5 to avoid timeouts.
if (getJitCompilerOptions()["ion.warmup.trigger"] < 5)
    setJitCompilerOption("ion.warmup.trigger", 5);

var ab = new ArrayBuffer(BUF_MIN);

// Compute a set of interesting indices.
indices = [0]
for (var i of [4,1024,BUF_MIN,Math.pow(2,30),Math.pow(2,31),Math.pow(2,32),Math.pow(2,33)]) {
    for (var j of [-2,-1,0,1,2]) {
        for (var k of [1,-1])
            indices.push((i+j)*k);
    }
}

function testInt(ctor, shift, scale, disp) {
    var arr = new ctor(ab);

    var c = asmCompile('glob', 'imp', 'b',
                       USE_ASM +
                       'var arr=new glob.' + ctor.name + '(b); ' +
                       'function load(i) {i=i|0; return arr[((i<<' + scale + ')+' + disp + ')>>' + shift + ']|0 } ' +
                       'function store(i,j) {i=i|0;j=j|0; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = j } ' +
                       'function storeZero(i) {i=i|0; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = 0 } ' +
                       'function storeNegOne(i) {i=i|0; arr[((i<<' + scale + ')+' + disp + ')>>' + shift + '] = -1 } ' +
                       'return { load: load, store: store, storeZero: storeZero, storeNegOne: storeNegOne }');
    var f = asmLink(c, this, null, ab);

    var v = 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment