// micro_ops.cm — microbenchmarks for core operations

function blackhole(sink, x) {
  return (sink + (x | 0)) | 0
}

function make_obj_xy(x, y) {
  return {x: x, y: y}
}

function make_obj_yx(x, y) {
  // Different insertion order to force a different shape
  return {y: y, x: x}
}

function make_shapes(n) {
  var out = []
  var i = 0
  var o = null
  for (i = 0; i < n; i++) {
    o = {a: i}
    o[`p${i}`] = i
    push(out, o)
  }
  return out
}

function make_packed_array(n) {
  var a = []
  var i = 0
  for (i = 0; i < n; i++) push(a, i)
  return a
}

function make_holey_array(n) {
  var a = []
  var i = 0
  for (i = 0; i < n; i += 2) a[i] = i
  return a
}

return {
  // 0) Baseline loop cost
  loop_empty: function(n) {
    var sink = 0
    var i = 0
    for (i = 0; i < n; i++) {}
    return blackhole(sink, n)
  },

  // 1) Numeric pipelines
  i32_add: function(n) {
    var sink = 0
    var x = 1
    var i = 0
    for (i = 0; i < n; i++) x = (x + 3) | 0
    return blackhole(sink, x)
  },

  f64_add: function(n) {
    var sink = 0
    var x = 1.0
    var i = 0
    for (i = 0; i < n; i++) x = x + 3.14159
    return blackhole(sink, x | 0)
  },

  mixed_add: function(n) {
    var sink = 0
    var x = 1
    var i = 0
    for (i = 0; i < n; i++) x = x + 0.25
    return blackhole(sink, x | 0)
  },

  bit_ops: function(n) {
    var sink = 0
    var x = 0x12345678
    var i = 0
    for (i = 0; i < n; i++) x = ((x << 5) ^ (x >>> 3)) | 0
    return blackhole(sink, x)
  },

  overflow_path: function(n) {
    var sink = 0
    var x = 0x70000000
    var i = 0
    for (i = 0; i < n; i++) x = (x + 0x10000000) | 0
    return blackhole(sink, x)
  },

  // 2) Branching
  branch_predictable: function(n) {
    var sink = 0
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      if ((i & 7) != 0) x++
      else x += 2
    }
    return blackhole(sink, x)
  },

  branch_alternating: function(n) {
    var sink = 0
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      if ((i & 1) == 0) x++
      else x += 2
    }
    return blackhole(sink, x)
  },

  // 3) Calls
  call_direct: function(n) {
    var sink = 0
    var f = function(a) { return (a + 1) | 0 }
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) x = f(x)
    return blackhole(sink, x)
  },

  call_indirect: function(n) {
    var sink = 0
    var f = function(a) { return (a + 1) | 0 }
    var g = f
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) x = g(x)
    return blackhole(sink, x)
  },

  call_closure: function(n) {
    var sink = 0
    var make_adder = function(k) {
      return function(a) { return (a + k) | 0 }
    }
    var add3 = make_adder(3)
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) x = add3(x)
    return blackhole(sink, x)
  },

  call_multi_arity: function(n) {
    var sink = 0
    var f0 = function() { return 1 }
    var f1 = function(a) { return a + 1 }
    var f2 = function(a, b) { return a + b }
    var f3 = function(a, b, c) { return a + b + c }
    var f4 = function(a, b, c, d) { return a + b + c + d }
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      x = (x + f0() + f1(i) + f2(i, 1) + f3(i, 1, 2) + f4(i, 1, 2, 3)) | 0
    }
    return blackhole(sink, x)
  },

  // 4) Object props (ICs / shapes)
  prop_read_mono: function(n) {
    var sink = 0
    var o = make_obj_xy(1, 2)
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) x = (x + o.x) | 0
    return blackhole(sink, x)
  },

  prop_read_poly_2: function(n) {
    var sink = 0
    var a = make_obj_xy(1, 2)
    var b = make_obj_yx(1, 2)
    var x = 0
    var i = 0
    var o = null
    for (i = 0; i < n; i++) {
      o = (i & 1) == 0 ? a : b
      x = (x + o.x) | 0
    }
    return blackhole(sink, x)
  },

  prop_read_poly_4: function(n) {
    var sink = 0
    var shapes = [
      {x: 1, y: 2},
      {y: 2, x: 1},
      {x: 1, z: 3, y: 2},
      {w: 0, x: 1, y: 2}
    ]
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      x = (x + shapes[i & 3].x) | 0
    }
    return blackhole(sink, x)
  },

  prop_read_mega: function(n) {
    var sink = 0
    var objs = make_shapes(32)
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      x = (x + objs[i & 31].a) | 0
    }
    return blackhole(sink, x)
  },

  prop_write_mono: function(n) {
    var sink = 0
    var o = make_obj_xy(1, 2)
    var i = 0
    for (i = 0; i < n; i++) o.x = (o.x + 1) | 0
    return blackhole(sink, o.x)
  },

  // 5) Arrays
  array_read_packed: function(n) {
    var sink = 0
    var a = make_packed_array(1024)
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) x = (x + a[i & 1023]) | 0
    return blackhole(sink, x)
  },

  array_write_packed: function(n) {
    var sink = 0
    var a = make_packed_array(1024)
    var i = 0
    for (i = 0; i < n; i++) a[i & 1023] = i
    return blackhole(sink, a[17] | 0)
  },

  array_read_holey: function(n) {
    var sink = 0
    var a = make_holey_array(2048)
    var x = 0
    var i = 0
    var v = null
    for (i = 0; i < n; i++) {
      v = a[(i & 2047)]
      if (v) x = (x + v) | 0
    }
    return blackhole(sink, x)
  },

  array_push_steady: function(n) {
    var sink = 0
    var x = 0
    var j = 0
    var i = 0
    var a = null
    for (j = 0; j < n; j++) {
      a = []
      for (i = 0; i < 256; i++) push(a, i)
      x = (x + length(a)) | 0
    }
    return blackhole(sink, x)
  },

  array_push_pop: function(n) {
    var sink = 0
    var a = []
    var x = 0
    var i = 0
    var v = 0
    for (i = 0; i < n; i++) {
      push(a, i)
      if (length(a) > 64) {
        v = pop(a)
        x = (x + v) | 0
      }
    }
    return blackhole(sink, x)
  },

  array_indexed_sum: function(n) {
    var sink = 0
    var a = make_packed_array(1024)
    var x = 0
    var j = 0
    var i = 0
    for (j = 0; j < n; j++) {
      x = 0
      for (i = 0; i < 1024; i++) {
        x = (x + a[i]) | 0
      }
    }
    return blackhole(sink, x)
  },

  // 6) Strings
  string_concat_small: function(n) {
    var sink = 0
    var x = 0
    var j = 0
    var i = 0
    var s = null
    for (j = 0; j < n; j++) {
      s = ""
      for (i = 0; i < 16; i++) s = s + "x"
      x = (x + length(s)) | 0
    }
    return blackhole(sink, x)
  },

  string_concat_medium: function(n) {
    var sink = 0
    var x = 0
    var j = 0
    var i = 0
    var s = null
    for (j = 0; j < n; j++) {
      s = ""
      for (i = 0; i < 100; i++) s = s + "abcdefghij"
      x = (x + length(s)) | 0
    }
    return blackhole(sink, x)
  },

  string_interpolation: function(n) {
    var sink = 0
    var x = 0
    var i = 0
    var s = null
    for (i = 0; i < n; i++) {
      s = `item_${i}_value_${i * 2}`
      x = (x + length(s)) | 0
    }
    return blackhole(sink, x)
  },

  string_slice: function(n) {
    var sink = 0
    var base = "the quick brown fox jumps over the lazy dog"
    var x = 0
    var i = 0
    var s = null
    for (i = 0; i < n; i++) {
      s = text(base, i % 10, i % 10 + 10)
      x = (x + length(s)) | 0
    }
    return blackhole(sink, x)
  },

  // 7) Allocation / GC pressure
  alloc_tiny_objects: function(n) {
    var sink = 0
    var x = 0
    var i = 0
    var o = null
    for (i = 0; i < n; i++) {
      o = {a: i, b: i + 1, c: i + 2}
      x = (x + o.b) | 0
    }
    return blackhole(sink, x)
  },

  alloc_linked_list: function(n) {
    var sink = 0
    var head = null
    var i = 0
    var x = 0
    var p = null
    for (i = 0; i < n; i++) head = {v: i, next: head}
    x = 0
    p = head
    while (p) {
      x = (x + p.v) | 0
      p = p.next
    }
    return blackhole(sink, x)
  },

  alloc_arrays: function(n) {
    var sink = 0
    var x = 0
    var i = 0
    var a = null
    for (i = 0; i < n; i++) {
      a = [i, i + 1, i + 2, i + 3]
      x = (x + a[2]) | 0
    }
    return blackhole(sink, x)
  },

  alloc_short_lived: function(n) {
    var sink = 0
    var x = 0
    var i = 0
    var o = null
    // Allocate objects that immediately become garbage
    for (i = 0; i < n; i++) {
      o = {val: i, data: {inner: i + 1}}
      x = (x + o.data.inner) | 0
    }
    return blackhole(sink, x)
  },

  alloc_long_lived_pressure: function(n) {
    var sink = 0
    var store = []
    var x = 0
    var i = 0
    var o = null
    // Keep first 1024 objects alive, churn the rest
    for (i = 0; i < n; i++) {
      o = {val: i, data: i * 2}
      if (i < 1024) {
        push(store, o)
      }
      x = (x + o.data) | 0
    }
    return blackhole(sink, x)
  },

  // 8) Meme (prototype clone)
  meme_clone_read: function(n) {
    var sink = 0
    var base = {x: 1, y: 2}
    var x = 0
    var i = 0
    var o = null
    for (i = 0; i < n; i++) {
      o = meme(base)
      x = (x + o.x) | 0
    }
    return blackhole(sink, x)
  },

  // 9) Guard / type check paths
  guard_hot_number: function(n) {
    // Monomorphic number path — guards should hoist
    var sink = 0
    var x = 1
    var i = 0
    for (i = 0; i < n; i++) x = x + 1
    return blackhole(sink, x | 0)
  },

  guard_mixed_types: function(n) {
    // Alternating number/text — guards must stay
    var sink = 0
    var vals = [1, "a", 2, "b", 3, "c", 4, "d"]
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      if (is_number(vals[i & 7])) x = (x + vals[i & 7]) | 0
    }
    return blackhole(sink, x)
  },

  // 10) Reduce / higher-order
  reduce_sum: function(n) {
    var sink = 0
    var a = make_packed_array(256)
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      x = (x + reduce(a, function(acc, v) { return acc + v }, 0)) | 0
    }
    return blackhole(sink, x)
  },

  filter_evens: function(n) {
    var sink = 0
    var a = make_packed_array(256)
    var x = 0
    var i = 0
    for (i = 0; i < n; i++) {
      x = (x + length(filter(a, function(v) { return v % 2 == 0 }))) | 0
    }
    return blackhole(sink, x)
  },

  arrfor_sum: function(n) {
    var sink = 0
    var a = make_packed_array(256)
    var x = 0
    var i = 0
    var sum = 0
    for (i = 0; i < n; i++) {
      sum = 0
      arrfor(a, function(v) { sum += v })
      x = (x + sum) | 0
    }
    return blackhole(sink, x)
  }
}
