describe("basic property access", () => {
    test("basic own property get", () => {
        const obj = { x: 1, y: 2, z: 3 };
        expect(obj.x).toBe(1);
        expect(obj.y).toBe(2);
        expect(obj.z).toBe(3);
    });

    test("basic own property set", () => {
        const obj = { x: 1 };
        obj.x = 42;
        expect(obj.x).toBe(42);
    });

    test("property get in loop (IC should kick in)", () => {
        const obj = { value: 100 };
        let sum = 0;
        for (let i = 0; i < 1000; i++) {
            sum += obj.value;
        }
        expect(sum).toBe(100000);
    });

    test("property set in loop (IC should kick in)", () => {
        const obj = { counter: 0 };
        for (let i = 0; i < 1000; i++) {
            obj.counter = i;
        }
        expect(obj.counter).toBe(999);
    });

    test("cached accessor get with missing getter", () => {
        function getValue(obj) {
            return obj.value;
        }

        const withGetter = {
            get value() {
                return 1;
            },
        };
        expect(getValue(withGetter)).toBe(1);

        const withSetter = {
            set value(value) {},
        };
        expect(getValue(withSetter)).toBeUndefined();
    });

    test("cached accessor set with missing setter", () => {
        function setValue(obj, value) {
            obj.value = value;
        }

        let setterValue = 0;
        const withSetter = {
            set value(value) {
                setterValue = value;
            },
        };
        setValue(withSetter, 1);
        expect(setterValue).toBe(1);

        const withGetter = {
            get value() {
                return 2;
            },
        };
        setValue(withGetter, 3);
        expect(withGetter.value).toBe(2);
    });
});

describe("prototype chain access", () => {
    test("single prototype chain get", () => {
        const proto = { inherited: 42 };
        const obj = Object.create(proto);
        obj.own = 1;
        expect(obj.inherited).toBe(42);
        expect(obj.own).toBe(1);
    });

    test("prototype chain get in loop", () => {
        const proto = { value: 5 };
        const obj = Object.create(proto);
        let sum = 0;
        for (let i = 0; i < 1000; i++) {
            sum += obj.value;
        }
        expect(sum).toBe(5000);
    });

    test("deep prototype chain (3 levels)", () => {
        const grandparent = { a: 1 };
        const parent = Object.create(grandparent);
        parent.b = 2;
        const child = Object.create(parent);
        child.c = 3;

        expect(child.a).toBe(1);
        expect(child.b).toBe(2);
        expect(child.c).toBe(3);
    });

    test("deep prototype chain (10 levels)", () => {
        let obj = { level: 0, base: "base" };
        for (let i = 1; i <= 10; i++) {
            obj = Object.create(obj);
            obj.level = i;
        }
        expect(obj.level).toBe(10);
        expect(obj.base).toBe("base");
    });

    test("prototype chain with null prototype", () => {
        const obj = Object.create(null);
        obj.x = 1;
        expect(obj.x).toBe(1);
        expect(obj.toString).toBeUndefined();
    });

    test("shadowing prototype property", () => {
        const proto = { x: 1 };
        const obj = Object.create(proto);
        expect(obj.x).toBe(1);
        obj.x = 2;
        expect(obj.x).toBe(2);
        expect(proto.x).toBe(1);
    });

    test("shadowing in loop", () => {
        const proto = { value: 100 };
        const objects = [];
        for (let i = 0; i < 100; i++) {
            const obj = Object.create(proto);
            if (i % 2 === 0) obj.value = i;
            objects.push(obj);
        }
        expect(objects[0].value).toBe(0);
        expect(objects[1].value).toBe(100);
        expect(objects[50].value).toBe(50);
        expect(objects[51].value).toBe(100);
    });
});

describe("shape transitions", () => {
    test("adding properties changes shape", () => {
        const obj = {};
        obj.a = 1;
        obj.b = 2;
        obj.c = 3;
        expect(obj.a).toBe(1);
        expect(obj.b).toBe(2);
        expect(obj.c).toBe(3);
    });

    test("same shape objects in loop", () => {
        const objects = [];
        for (let i = 0; i < 100; i++) {
            objects.push({ x: i, y: i * 2 });
        }
        let sum = 0;
        for (const obj of objects) {
            sum += obj.x + obj.y;
        }
        expect(sum).toBe(14850);
    });

    test("different shape objects in loop (IC polymorphism)", () => {
        const objects = [];
        for (let i = 0; i < 100; i++) {
            if (i % 3 === 0) objects.push({ x: i });
            else if (i % 3 === 1) objects.push({ x: i, y: 1 });
            else objects.push({ x: i, y: 1, z: 2 });
        }
        let sum = 0;
        for (const obj of objects) {
            sum += obj.x;
        }
        expect(sum).toBe(4950);
    });

    test("megamorphic IC (many different shapes)", () => {
        const objects = [];
        for (let i = 0; i < 100; i++) {
            const obj = {};
            for (let j = 0; j <= i % 20; j++) {
                obj["prop" + j] = j;
            }
            obj.common = i;
            objects.push(obj);
        }
        let sum = 0;
        for (const obj of objects) {
            sum += obj.common;
        }
        expect(sum).toBe(4950);
    });
});

describe("property deletion", () => {
    test("delete own property", () => {
        const obj = { x: 1, y: 2 };
        expect(obj.x).toBe(1);
        delete obj.x;
        expect(obj.x).toBeUndefined();
        expect(obj.y).toBe(2);
    });

    test("delete then re-add", () => {
        const obj = { x: 1 };
        delete obj.x;
        obj.x = 2;
        expect(obj.x).toBe(2);
    });

    test("delete exposes prototype property", () => {
        const proto = { x: "proto" };
        const obj = Object.create(proto);
        obj.x = "own";
        expect(obj.x).toBe("own");
        delete obj.x;
        expect(obj.x).toBe("proto");
    });

    test("delete in loop affects IC", () => {
        const objects = [];
        for (let i = 0; i < 100; i++) {
            const obj = { x: i, y: i * 2 };
            if (i % 2 === 0) delete obj.x;
            objects.push(obj);
        }
        let undefinedCount = 0;
        for (const obj of objects) {
            if (obj.x === undefined) undefinedCount++;
        }
        expect(undefinedCount).toBe(50);
    });
});

describe("getters and setters", () => {
    test("own getter", () => {
        const obj = {
            _x: 10,
            get x() {
                return this._x * 2;
            },
        };
        expect(obj.x).toBe(20);
    });

    test("own setter", () => {
        const obj = {
            _x: 0,
            set x(v) {
                this._x = v * 2;
            },
        };
        obj.x = 5;
        expect(obj._x).toBe(10);
    });

    test("prototype getter", () => {
        const proto = {
            get value() {
                return 42;
            },
        };
        const obj = Object.create(proto);
        expect(obj.value).toBe(42);
    });

    test("prototype setter", () => {
        const proto = {
            _value: 0,
            set value(v) {
                this._value = v;
            },
        };
        const obj = Object.create(proto);
        obj.value = 100;
        expect(obj._value).toBe(100);
        expect(proto._value).toBe(0);
    });

    test("getter in loop", () => {
        const obj = {
            _counter: 0,
            get counter() {
                return this._counter++;
            },
        };
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += obj.counter;
        }
        expect(sum).toBe(4950);
    });

    test("setter in loop", () => {
        const obj = {
            _value: 0,
            set value(v) {
                this._value += v;
            },
        };
        for (let i = 0; i < 100; i++) {
            obj.value = 1;
        }
        expect(obj._value).toBe(100);
    });

    test("shadowing getter with data property", () => {
        const proto = {
            get x() {
                return "getter";
            },
        };
        const obj = Object.create(proto);
        expect(obj.x).toBe("getter");
        Object.defineProperty(obj, "x", { value: "data", writable: true });
        expect(obj.x).toBe("data");
    });

    test("getter returning different values based on state", () => {
        const obj = {
            state: 0,
            get dynamic() {
                return this.state++;
            },
        };
        const results = [];
        for (let i = 0; i < 10; i++) {
            results.push(obj.dynamic);
        }
        expect(results).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    });
});

describe("Object.defineProperty", () => {
    test("defineProperty non-writable", () => {
        const obj = {};
        Object.defineProperty(obj, "x", { value: 1, writable: false });
        expect(obj.x).toBe(1);
        obj.x = 2;
        expect(obj.x).toBe(1);
    });

    test("defineProperty non-configurable", () => {
        const obj = {};
        Object.defineProperty(obj, "x", { value: 1, configurable: false });
        expect(obj.x).toBe(1);
        expect(() => {
            Object.defineProperty(obj, "x", { value: 2 });
        }).toThrow(TypeError);
    });

    test("defineProperty on prototype affects lookup", () => {
        const proto = {};
        const obj = Object.create(proto);
        expect(obj.x).toBeUndefined();
        Object.defineProperty(proto, "x", { value: 42 });
        expect(obj.x).toBe(42);
    });

    test("convert data to accessor", () => {
        const obj = { x: 1 };
        expect(obj.x).toBe(1);
        Object.defineProperty(obj, "x", {
            get() {
                return 100;
            },
            configurable: true,
        });
        expect(obj.x).toBe(100);
    });

    test("convert accessor to data", () => {
        const obj = {
            get x() {
                return 1;
            },
        };
        expect(obj.x).toBe(1);
        Object.defineProperty(obj, "x", { value: 100, configurable: true, writable: true });
        expect(obj.x).toBe(100);
    });
});

describe("prototype manipulation", () => {
    test("changing __proto__ at runtime", () => {
        const proto1 = { x: 1 };
        const proto2 = { x: 2 };
        const obj = Object.create(proto1);
        expect(obj.x).toBe(1);
        Object.setPrototypeOf(obj, proto2);
        expect(obj.x).toBe(2);
    });

    test("changing __proto__ in loop", () => {
        const proto1 = { value: 1 };
        const proto2 = { value: 2 };
        const obj = Object.create(proto1);

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            if (i === 50) Object.setPrototypeOf(obj, proto2);
            sum += obj.value;
        }
        expect(sum).toBe(150);
    });

    test("null prototype then add new prototype", () => {
        const obj = Object.create(null);
        obj.x = 1;
        expect(obj.x).toBe(1);
        expect(obj.toString).toBeUndefined();

        Object.setPrototypeOf(obj, {
            y: 2,
            toString() {
                return "obj";
            },
        });
        expect(obj.x).toBe(1);
        expect(obj.y).toBe(2);
        expect(obj.toString()).toBe("obj");
    });

    test("cyclic prototype chain attempt", () => {
        const a = {};
        const b = Object.create(a);
        expect(() => {
            Object.setPrototypeOf(a, b);
        }).toThrow(TypeError);
    });
});

describe("proxy objects", () => {
    test("proxy get trap", () => {
        const target = { x: 1 };
        const proxy = new Proxy(target, {
            get(t, prop) {
                return t[prop] * 2;
            },
        });
        expect(proxy.x).toBe(2);
    });

    test("proxy set trap", () => {
        const target = { x: 1 };
        const proxy = new Proxy(target, {
            set(t, prop, value) {
                t[prop] = value * 2;
                return true;
            },
        });
        proxy.x = 5;
        expect(target.x).toBe(10);
    });

    test("proxy in prototype chain", () => {
        const protoTarget = { inherited: 42 };
        const protoProxy = new Proxy(protoTarget, {
            get(t, prop) {
                if (prop === "inherited") return t[prop] + 1;
                return t[prop];
            },
        });
        const obj = Object.create(protoProxy);
        obj.own = 1;
        expect(obj.inherited).toBe(43);
        expect(obj.own).toBe(1);
    });

    test("proxy get trap in loop", () => {
        let getCount = 0;
        const proxy = new Proxy(
            { x: 10 },
            {
                get(t, prop) {
                    getCount++;
                    return t[prop];
                },
            }
        );
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += proxy.x;
        }
        expect(sum).toBe(1000);
        expect(getCount).toBe(100);
    });

    test("proxy that returns different values", () => {
        let counter = 0;
        const proxy = new Proxy(
            {},
            {
                get(t, prop) {
                    return counter++;
                },
            }
        );
        const results = [];
        for (let i = 0; i < 5; i++) {
            results.push(proxy.x);
        }
        expect(results).toEqual([0, 1, 2, 3, 4]);
    });
});

describe("special object types", () => {
    test("array length property", () => {
        const arr = [1, 2, 3];
        expect(arr.length).toBe(3);
        arr.length = 2;
        expect(arr.length).toBe(2);
        expect(arr[2]).toBeUndefined();
    });

    test("array index access", () => {
        const arr = [10, 20, 30];
        let sum = 0;
        for (let i = 0; i < 1000; i++) {
            sum += arr[i % 3];
        }
        expect(sum).toBe(19990);
    });

    test("array with holes", () => {
        const arr = [1, , 3];
        expect(arr[0]).toBe(1);
        expect(arr[1]).toBeUndefined();
        expect(arr[2]).toBe(3);
        expect(1 in arr).toBeFalse();
    });

    test("array prototype method access", () => {
        const arr = [1, 2, 3];
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += arr.reduce((a, b) => a + b, 0);
        }
        expect(sum).toBe(600);
    });

    test("typed array property access", () => {
        const arr = new Int32Array([1, 2, 3, 4, 5]);
        let sum = 0;
        for (let i = 0; i < 1000; i++) {
            sum += arr[i % 5];
        }
        expect(sum).toBe(3000);
    });

    test("string index access", () => {
        const str = "hello";
        let result = "";
        for (let i = 0; i < str.length; i++) {
            result += str[i];
        }
        expect(result).toBe("hello");
    });

    test("string length property", () => {
        const str = "hello";
        expect(str.length).toBe(5);
    });

    test("function properties", () => {
        function foo() {}
        foo.custom = 42;
        expect(foo.custom).toBe(42);
        expect(foo.name).toBe("foo");
        expect(typeof foo.prototype).toBe("object");
    });

    test("arguments object", () => {
        function test() {
            expect(arguments[0]).toBe(1);
            expect(arguments[1]).toBe(2);
            expect(arguments.length).toBe(3);
        }
        test(1, 2, 3);
    });
});

describe("symbol properties", () => {
    test("symbol property access", () => {
        const sym = Symbol("test");
        const obj = { [sym]: 42 };
        expect(obj[sym]).toBe(42);
    });

    test("symbol in prototype", () => {
        const sym = Symbol("inherited");
        const proto = { [sym]: "proto" };
        const obj = Object.create(proto);
        expect(obj[sym]).toBe("proto");
    });

    test("well-known symbols", () => {
        const obj = {
            [Symbol.toStringTag]: "Custom",
        };
        expect(Object.prototype.toString.call(obj)).toBe("[object Custom]");
    });

    test("symbol property iteration", () => {
        const sym1 = Symbol("a");
        const sym2 = Symbol("b");
        const obj = { [sym1]: 1, [sym2]: 2, regular: 3 };

        const symbols = Object.getOwnPropertySymbols(obj);
        expect(symbols.length).toBe(2);
        expect(obj[symbols[0]]).toBe(1);
        expect(obj[symbols[1]]).toBe(2);
    });
});

describe("computed property names", () => {
    test("computed property get", () => {
        const obj = { a: 1, b: 2, c: 3 };
        const keys = ["a", "b", "c"];
        let sum = 0;
        for (const key of keys) {
            sum += obj[key];
        }
        expect(sum).toBe(6);
    });

    test("computed property set", () => {
        const obj = {};
        const keys = ["a", "b", "c"];
        for (let i = 0; i < keys.length; i++) {
            obj[keys[i]] = i;
        }
        expect(obj.a).toBe(0);
        expect(obj.b).toBe(1);
        expect(obj.c).toBe(2);
    });

    test("computed property with numbers", () => {
        const obj = {};
        for (let i = 0; i < 100; i++) {
            obj[i] = i * 2;
        }
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += obj[i];
        }
        expect(sum).toBe(9900);
    });

    test("computed property coercion", () => {
        const obj = {};
        obj[1] = "one";
        obj["1"] = "one-string";
        expect(obj[1]).toBe("one-string");
        expect(obj["1"]).toBe("one-string");
    });
});

describe("constructor patterns", () => {
    test("constructor instance properties", () => {
        function Point(x, y) {
            this.x = x;
            this.y = y;
        }
        const points = [];
        for (let i = 0; i < 100; i++) {
            points.push(new Point(i, i * 2));
        }
        let sumX = 0,
            sumY = 0;
        for (const p of points) {
            sumX += p.x;
            sumY += p.y;
        }
        expect(sumX).toBe(4950);
        expect(sumY).toBe(9900);
    });

    test("constructor prototype methods", () => {
        function Counter() {
            this.value = 0;
        }
        Counter.prototype.increment = function () {
            this.value++;
        };
        Counter.prototype.get = function () {
            return this.value;
        };

        const c = new Counter();
        for (let i = 0; i < 100; i++) {
            c.increment();
        }
        expect(c.get()).toBe(100);
    });

    test("class instance properties", () => {
        class Point {
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }
        }
        const points = [];
        for (let i = 0; i < 100; i++) {
            points.push(new Point(i, i * 2));
        }
        let sumX = 0,
            sumY = 0;
        for (const p of points) {
            sumX += p.x;
            sumY += p.y;
        }
        expect(sumX).toBe(4950);
        expect(sumY).toBe(9900);
    });

    test("class with getters/setters", () => {
        class Box {
            constructor(v) {
                this._v = v;
            }
            get value() {
                return this._v * 2;
            }
            set value(v) {
                this._v = v / 2;
            }
        }
        const b = new Box(10);
        expect(b.value).toBe(20);
        b.value = 100;
        expect(b._v).toBe(50);
        expect(b.value).toBe(100);
    });

    test("class inheritance", () => {
        class Animal {
            constructor(name) {
                this.name = name;
            }
            speak() {
                return "...";
            }
        }
        class Dog extends Animal {
            speak() {
                return "woof";
            }
        }
        class Cat extends Animal {
            speak() {
                return "meow";
            }
        }

        const animals = [new Dog("Rex"), new Cat("Whiskers"), new Dog("Buddy")];
        const sounds = animals.map(a => a.speak());
        expect(sounds).toEqual(["woof", "meow", "woof"]);
    });

    test("class static properties", () => {
        class Counter {
            static count = 0;
            constructor() {
                Counter.count++;
            }
        }
        for (let i = 0; i < 10; i++) {
            new Counter();
        }
        expect(Counter.count).toBe(10);
    });
});

describe("edge cases", () => {
    test("property named __proto__", () => {
        const obj = Object.create(null);
        obj.__proto__ = 42;
        expect(obj.__proto__).toBe(42);
    });

    test("property named constructor", () => {
        const obj = { constructor: 42 };
        expect(obj.constructor).toBe(42);
    });

    test("numeric string keys vs number keys", () => {
        const obj = {};
        obj["0"] = "string";
        expect(obj[0]).toBe("string");
        obj[0] = "number";
        expect(obj["0"]).toBe("number");
    });

    test("very long property name", () => {
        const longName = "a".repeat(1000);
        const obj = { [longName]: 42 };
        expect(obj[longName]).toBe(42);
    });

    test("property access on primitives", () => {
        expect((42).toString()).toBe("42");
        expect("hello".toUpperCase()).toBe("HELLO");
        expect(true.toString()).toBe("true");
    });

    test("undefined/null property access", () => {
        expect(() => null.x).toThrow(TypeError);
        expect(() => undefined.x).toThrow(TypeError);
    });

    test("hasOwnProperty vs in operator", () => {
        const proto = { inherited: 1 };
        const obj = Object.create(proto);
        obj.own = 2;

        expect("own" in obj).toBeTrue();
        expect("inherited" in obj).toBeTrue();
        expect(obj.hasOwnProperty("own")).toBeTrue();
        expect(obj.hasOwnProperty("inherited")).toBeFalse();
    });

    test("Object.keys vs Object.getOwnPropertyNames", () => {
        const obj = {};
        Object.defineProperty(obj, "hidden", { value: 1, enumerable: false });
        obj.visible = 2;

        expect(Object.keys(obj)).toEqual(["visible"]);
        expect(Object.getOwnPropertyNames(obj).sort()).toEqual(["hidden", "visible"]);
    });

    test("frozen object property access", () => {
        const obj = Object.freeze({ x: 1, y: 2 });
        expect(obj.x).toBe(1);
        obj.x = 100;
        expect(obj.x).toBe(1);
        obj.z = 3;
        expect(obj.z).toBeUndefined();
    });

    test("sealed object property access", () => {
        const obj = Object.seal({ x: 1 });
        expect(obj.x).toBe(1);
        obj.x = 100;
        expect(obj.x).toBe(100);
        obj.y = 2;
        expect(obj.y).toBeUndefined();
    });

    test("non-extensible object", () => {
        const obj = Object.preventExtensions({ x: 1 });
        obj.x = 2;
        expect(obj.x).toBe(2);
        obj.y = 3;
        expect(obj.y).toBeUndefined();
    });
});

describe("prototype mutations during access", () => {
    test("modify prototype during iteration", () => {
        const proto = { a: 1, b: 2 };
        const obj = Object.create(proto);

        const values = [];
        for (const key in obj) {
            values.push(obj[key]);
            if (key === "a") proto.c = 3;
        }
        expect(obj.c).toBe(3);
    });

    test("delete prototype property during access", () => {
        const proto = { x: 1 };
        const obj = Object.create(proto);

        expect(obj.x).toBe(1);
        delete proto.x;
        expect(obj.x).toBeUndefined();
    });

    test("add own property shadows prototype during loop", () => {
        const proto = { value: "proto" };
        const objects = [];
        for (let i = 0; i < 10; i++) {
            objects.push(Object.create(proto));
        }

        const results = [];
        for (let i = 0; i < objects.length; i++) {
            results.push(objects[i].value);
            if (i === 4) objects[5].value = "own";
        }
        expect(results).toEqual([
            "proto",
            "proto",
            "proto",
            "proto",
            "proto",
            "own",
            "proto",
            "proto",
            "proto",
            "proto",
        ]);
    });
});

describe("mixed access patterns", () => {
    test("alternating get and set", () => {
        const obj = { x: 0 };
        for (let i = 0; i < 100; i++) {
            obj.x = obj.x + 1;
        }
        expect(obj.x).toBe(100);
    });

    test("multiple objects same shape alternating access", () => {
        const a = { x: 1, y: 2 };
        const b = { x: 10, y: 20 };
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += i % 2 === 0 ? a.x + a.y : b.x + b.y;
        }
        expect(sum).toBe(1650);
    });

    test("property access through variable", () => {
        const obj = { a: 1, b: 2, c: 3 };
        const props = ["a", "b", "c", "a", "b", "c"];
        let sum = 0;
        for (const p of props) {
            sum += obj[p];
        }
        expect(sum).toBe(12);
    });

    test("nested object access", () => {
        const obj = {
            level1: {
                level2: {
                    level3: {
                        value: 42,
                    },
                },
            },
        };
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += obj.level1.level2.level3.value;
        }
        expect(sum).toBe(4200);
    });

    test("optional chaining", () => {
        const obj = { a: { b: { c: 42 } } };
        expect(obj?.a?.b?.c).toBe(42);
        expect(obj?.x?.y?.z).toBeUndefined();
        expect(null?.x).toBeUndefined();
    });
});

describe("IC invalidation scenarios", () => {
    test("IC invalidation by adding property to prototype", () => {
        const proto = {};
        const objects = [];
        for (let i = 0; i < 10; i++) {
            objects.push(Object.create(proto));
        }

        for (let i = 0; i < 100; i++) {
            for (const obj of objects) {
                obj.x;
            }
        }

        proto.x = 42;

        let sum = 0;
        for (const obj of objects) {
            sum += obj.x;
        }
        expect(sum).toBe(420);
    });

    test("IC invalidation by deleting property from prototype", () => {
        const proto = { x: 42 };
        const obj = Object.create(proto);

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += obj.x;
        }
        expect(sum).toBe(4200);

        delete proto.x;

        expect(obj.x).toBeUndefined();
    });

    test("IC with changing object shapes", () => {
        function getValue(obj) {
            return obj.value;
        }

        const obj1 = { value: 1 };
        const obj2 = { a: 0, value: 2 };
        const obj3 = { a: 0, b: 0, value: 3 };

        expect(getValue(obj1)).toBe(1);
        expect(getValue(obj2)).toBe(2);
        expect(getValue(obj3)).toBe(3);
        expect(getValue(obj1)).toBe(1);
        expect(getValue(obj2)).toBe(2);
    });
});

describe("global object access", () => {
    test("global property access", () => {
        globalThis.testGlobal = 42;
        expect(testGlobal).toBe(42);
        delete globalThis.testGlobal;
    });

    test("global property in loop", () => {
        globalThis.loopCounter = 0;
        for (let i = 0; i < 100; i++) {
            loopCounter++;
        }
        expect(loopCounter).toBe(100);
        delete globalThis.loopCounter;
    });
});

describe("Reflect API", () => {
    test("Reflect.get", () => {
        const obj = { x: 42 };
        expect(Reflect.get(obj, "x")).toBe(42);
    });

    test("Reflect.set", () => {
        const obj = { x: 1 };
        Reflect.set(obj, "x", 42);
        expect(obj.x).toBe(42);
    });

    test("Reflect.get with receiver", () => {
        const proto = {
            get x() {
                return this.y * 2;
            },
        };
        const obj = Object.create(proto);
        obj.y = 10;
        expect(Reflect.get(proto, "x", obj)).toBe(20);
    });

    test("Reflect.has", () => {
        const proto = { inherited: 1 };
        const obj = Object.create(proto);
        obj.own = 2;
        expect(Reflect.has(obj, "own")).toBeTrue();
        expect(Reflect.has(obj, "inherited")).toBeTrue();
        expect(Reflect.has(obj, "missing")).toBeFalse();
    });
});

describe("Map/WeakMap", () => {
    test("Map property-like access pattern", () => {
        const map = new Map();
        map.set("x", 1);
        map.set("y", 2);

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += map.get("x") + map.get("y");
        }
        expect(sum).toBe(300);
    });

    test("WeakMap with object keys", () => {
        const wm = new WeakMap();
        const keys = [];
        for (let i = 0; i < 10; i++) {
            const key = {};
            keys.push(key);
            wm.set(key, i);
        }

        let sum = 0;
        for (const key of keys) {
            sum += wm.get(key);
        }
        expect(sum).toBe(45);
    });
});

describe("super property access", () => {
    test("super property get", () => {
        class Parent {
            getValue() {
                return 42;
            }
        }
        class Child extends Parent {
            getValue() {
                return super.getValue() * 2;
            }
        }
        const c = new Child();
        expect(c.getValue()).toBe(84);
    });

    test("super property get in loop", () => {
        class Parent {
            getValue() {
                return 1;
            }
        }
        class Child extends Parent {
            getValue() {
                return super.getValue() + 1;
            }
        }
        const c = new Child();
        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += c.getValue();
        }
        expect(sum).toBe(200);
    });

    test("super with getter", () => {
        class Parent {
            get value() {
                return 10;
            }
        }
        class Child extends Parent {
            get value() {
                return super.value * 2;
            }
        }
        const c = new Child();
        expect(c.value).toBe(20);
    });
});

describe("polymorphic IC boundary tests", () => {
    test("monomorphic IC (1 shape)", () => {
        function getValue(obj) {
            return obj.x;
        }
        const objects = [];
        for (let i = 0; i < 100; i++) {
            objects.push({ x: i });
        }
        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);
    });

    test("dimorphic IC (2 shapes)", () => {
        function getValue(obj) {
            return obj.x;
        }
        const shape1 = [];
        const shape2 = [];
        for (let i = 0; i < 50; i++) {
            shape1.push({ x: i });
            shape2.push({ x: i, y: 0 });
        }
        let sum = 0;
        for (let i = 0; i < 50; i++) {
            sum += getValue(shape1[i]);
            sum += getValue(shape2[i]);
        }
        expect(sum).toBe(2450);
    });

    test("trimorphic IC (3 shapes)", () => {
        function getValue(obj) {
            return obj.x;
        }
        const objects = [];
        for (let i = 0; i < 99; i++) {
            if (i % 3 === 0) objects.push({ x: i });
            else if (i % 3 === 1) objects.push({ x: i, y: 0 });
            else objects.push({ x: i, y: 0, z: 0 });
        }
        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4851);
    });

    test("tetramorphic IC (4 shapes - at limit)", () => {
        function getValue(obj) {
            return obj.x;
        }
        const objects = [];
        for (let i = 0; i < 100; i++) {
            if (i % 4 === 0) objects.push({ x: i });
            else if (i % 4 === 1) objects.push({ x: i, a: 0 });
            else if (i % 4 === 2) objects.push({ x: i, b: 0 });
            else objects.push({ x: i, c: 0 });
        }
        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);
    });

    test("pentamorphic IC (5 shapes - exceeds limit)", () => {
        function getValue(obj) {
            return obj.x;
        }
        const objects = [];
        for (let i = 0; i < 100; i++) {
            if (i % 5 === 0) objects.push({ x: i });
            else if (i % 5 === 1) objects.push({ x: i, a: 0 });
            else if (i % 5 === 2) objects.push({ x: i, b: 0 });
            else if (i % 5 === 3) objects.push({ x: i, c: 0 });
            else objects.push({ x: i, d: 0 });
        }
        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);
    });

    test("megamorphic IC (20 shapes)", () => {
        function getValue(obj) {
            return obj.x;
        }
        const objects = [];
        for (let i = 0; i < 100; i++) {
            const obj = { x: i };
            for (let j = 0; j < i % 20; j++) {
                obj["prop" + j] = j;
            }
            objects.push(obj);
        }
        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);
    });

    test("polymorphic IC with prototype differences", () => {
        function getValue(obj) {
            return obj.x;
        }
        const proto1 = { type: 1 };
        const proto2 = { type: 2 };
        const proto3 = { type: 3 };
        const proto4 = { type: 4 };

        const objects = [];
        for (let i = 0; i < 100; i++) {
            let obj;
            if (i % 4 === 0) obj = Object.create(proto1);
            else if (i % 4 === 1) obj = Object.create(proto2);
            else if (i % 4 === 2) obj = Object.create(proto3);
            else obj = Object.create(proto4);
            obj.x = i;
            objects.push(obj);
        }
        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);
    });

    test("polymorphic setter IC (4 shapes)", () => {
        function setValue(obj, v) {
            obj.x = v;
        }
        const objects = [];
        for (let i = 0; i < 100; i++) {
            if (i % 4 === 0) objects.push({});
            else if (i % 4 === 1) objects.push({ a: 0 });
            else if (i % 4 === 2) objects.push({ b: 0 });
            else objects.push({ c: 0 });
        }
        for (let i = 0; i < objects.length; i++) {
            setValue(objects[i], i);
        }
        let sum = 0;
        for (const obj of objects) {
            sum += obj.x;
        }
        expect(sum).toBe(4950);
    });

    test("polymorphic IC interleaved access patterns", () => {
        function getValue(obj) {
            return obj.value;
        }

        const a = { value: 1 };
        const b = { value: 2, extra1: 0 };
        const c = { value: 3, extra1: 0, extra2: 0 };
        const d = { value: 4, extra1: 0, extra2: 0, extra3: 0 };

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(a);
            sum += getValue(b);
            sum += getValue(c);
            sum += getValue(d);
        }
        expect(sum).toBe(1000);

        for (let i = 0; i < 100; i++) {
            sum += getValue(d);
            sum += getValue(c);
            sum += getValue(b);
            sum += getValue(a);
        }
        expect(sum).toBe(2000);
    });

    test("polymorphic IC with shape transition during access", () => {
        function getValue(obj) {
            return obj.x;
        }

        const objects = [];
        for (let i = 0; i < 100; i++) {
            objects.push({ x: i });
        }

        let sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);

        for (let i = 0; i < 25; i++) {
            objects[i].a = 0;
        }
        for (let i = 25; i < 50; i++) {
            objects[i].b = 0;
        }
        for (let i = 50; i < 75; i++) {
            objects[i].c = 0;
        }

        sum = 0;
        for (const obj of objects) {
            sum += getValue(obj);
        }
        expect(sum).toBe(4950);
    });

    test("polymorphic IC crossing 4-shape boundary", () => {
        function getValue(obj) {
            return obj.x;
        }

        const objects = [{ x: 1 }, { x: 2, a: 0 }, { x: 3, b: 0 }, { x: 4, c: 0 }];

        for (let i = 0; i < 100; i++) {
            for (const obj of objects) {
                getValue(obj);
            }
        }

        objects.push({ x: 5, d: 0 });

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            for (const obj of objects) {
                sum += getValue(obj);
            }
        }
        expect(sum).toBe(1500);
    });

    test("polymorphic IC with getters mixed in", () => {
        function getValue(obj) {
            return obj.x;
        }

        const regular1 = { x: 1 };
        const regular2 = { x: 2, y: 0 };
        const withGetter1 = {
            get x() {
                return 3;
            },
        };
        const withGetter2 = {
            get x() {
                return 4;
            },
            y: 0,
        };

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(regular1);
            sum += getValue(regular2);
            sum += getValue(withGetter1);
            sum += getValue(withGetter2);
        }
        expect(sum).toBe(1000);
    });

    test("polymorphic IC with null prototype objects", () => {
        function getValue(obj) {
            return obj.x;
        }

        const regular = { x: 1 };
        const nullProto = Object.create(null);
        nullProto.x = 2;
        const nullProto2 = Object.create(null);
        nullProto2.x = 3;
        nullProto2.y = 0;

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(regular);
            sum += getValue(nullProto);
            sum += getValue(nullProto2);
        }
        expect(sum).toBe(600);
    });

    test("polymorphic IC stress - rapid shape changes", () => {
        function getValue(obj) {
            return obj.x;
        }

        let sum = 0;
        for (let i = 0; i < 1000; i++) {
            const obj = { x: i };
            for (let j = 0; j < i % 10; j++) {
                obj["p" + j] = 0;
            }
            sum += getValue(obj);
        }
        expect(sum).toBe(499500);
    });

    test("polymorphic IC - same property different positions", () => {
        function getValue(obj) {
            return obj.target;
        }

        const a = { target: 1 };
        const b = { a: 0, target: 2 };
        const c = { a: 0, b: 0, target: 3 };
        const d = { a: 0, b: 0, c: 0, target: 4 };

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(a) + getValue(b) + getValue(c) + getValue(d);
        }
        expect(sum).toBe(1000);
    });

    test("polymorphic IC - property in prototype at different depths", () => {
        function getValue(obj) {
            return obj.inherited;
        }

        const proto1 = { inherited: 1 };
        const proto2a = Object.create({ inherited: 2 });
        const proto2b = { other: 0 };
        proto2b.inherited = 3;

        const obj1 = Object.create(proto1);
        const obj2 = Object.create(proto2a);
        const obj3 = Object.create(proto2b);
        const obj4 = { inherited: 4 };

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(obj1) + getValue(obj2) + getValue(obj3) + getValue(obj4);
        }
        expect(sum).toBe(1000);
    });

    test("polymorphic setter IC with shape transitions", () => {
        function setValue(obj, v) {
            obj.x = v;
        }

        const objects = [];
        for (let i = 0; i < 100; i++) {
            objects.push({});
        }

        for (let i = 0; i < 100; i++) {
            setValue(objects[i], i);
        }

        let sum = 0;
        for (const obj of objects) {
            sum += obj.x;
        }
        expect(sum).toBe(4950);

        for (let i = 0; i < 100; i++) {
            objects[i]["extra" + (i % 4)] = 0;
        }

        for (let i = 0; i < 100; i++) {
            setValue(objects[i], i * 2);
        }

        sum = 0;
        for (const obj of objects) {
            sum += obj.x;
        }
        expect(sum).toBe(9900);
    });

    test("polymorphic IC with frozen/sealed objects", () => {
        function getValue(obj) {
            return obj.x;
        }

        const regular = { x: 1 };
        const frozen = Object.freeze({ x: 2 });
        const sealed = Object.seal({ x: 3 });
        const nonExtensible = Object.preventExtensions({ x: 4 });

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(regular);
            sum += getValue(frozen);
            sum += getValue(sealed);
            sum += getValue(nonExtensible);
        }
        expect(sum).toBe(1000);
    });

    test("polymorphic IC - array vs object", () => {
        function getFirst(obj) {
            return obj[0];
        }

        const arr = [42];
        const obj = { 0: 42 };
        const typedArr = new Int32Array([42]);

        let sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getFirst(arr);
            sum += getFirst(obj);
            sum += getFirst(typedArr);
        }
        expect(sum).toBe(12600);
    });

    test("IC cache thrashing - alternating hot/cold", () => {
        function getValue(obj) {
            return obj.x;
        }

        const shapes = [];
        for (let i = 0; i < 8; i++) {
            const obj = { x: i + 1 };
            for (let j = 0; j < i; j++) {
                obj["prop" + j] = 0;
            }
            shapes.push(obj);
        }

        let sum = 0;
        for (let i = 0; i < 800; i++) {
            sum += getValue(shapes[i % 8]);
        }
        expect(sum).toBe(3600);
    });

    test("IC with computed property becoming constant", () => {
        function getValue(obj, prop) {
            return obj[prop];
        }

        const obj = { a: 1, b: 2, c: 3, d: 4 };

        let sum = 0;
        const props = ["a", "b", "c", "d"];
        for (let i = 0; i < 100; i++) {
            sum += getValue(obj, props[i % 4]);
        }
        expect(sum).toBe(250);

        sum = 0;
        for (let i = 0; i < 100; i++) {
            sum += getValue(obj, "a");
        }
        expect(sum).toBe(100);
    });
});
