Bug 928928 - Add missing property GetProp stub in BaselineJIT. r=nbp
authorKannan Vijayan <kvijayan@mozilla.com>
Fri, 27 Jun 2014 13:35:24 -0400
changeset 191257 95ce6d0c7993c545a70fd376a7bda5ac33dad7b6
parent 191256 9dafb9b56b5c2c98bcef593b863087b8c573a41a
child 191258 49a9a330ce39c3122aeb81527710f9a1560dfbc7
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersnbp
bugs928928
milestone33.0a1
Bug 928928 - Add missing property GetProp stub in BaselineJIT. r=nbp
js/src/jit-test/etc/generate-nosuchproperty-tests.js
js/src/jit-test/tests/baseline/no-such-property-getprop.js
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/etc/generate-nosuchproperty-tests.js
@@ -0,0 +1,78 @@
+
+// This code generates the test cases jit-test/tests/baseline/no-such-property-getprop.js
+//
+// In particular, it generates the testChain_<N>_<I>() and runChain_<N>_<I>() functions
+// at the tail of the file.
+
+var TEST_CASE_FUNCS =  [];
+function runChain_NNNN_DDDD(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_NNNN_DDDD() {
+    var obj = createTower(NNNN);
+    assertEq(runChain_NNNN_DDDD(obj), NaN);
+    updateChain(obj, DDDD, 'foo', 9);
+    assertEq(runChain_NNNN_DDDD(obj), 900);
+}
+function generateTestCase(n, d) {
+    var runFuncName = "runChain_" + n + "_" + d;
+    var testFuncName = "testChain_" + n + "_" + d;
+    TEST_CASE_FUNCS.push(testFuncName);
+
+    print("//// Test chain of length " + n + " with late-property-addition at depth " + d);
+    print(uneval(runChain_NNNN_DDDD).replace(/NNNN/g, ''+n).replace(/DDDD/g, ''+d));
+    print(uneval(testChain_NNNN_DDDD).replace(/NNNN/g, ''+n).replace(/DDDD/g, ''+d));
+    print("");
+}
+
+// Helper function to create an object with a proto-chain of length N.
+function createTower(n) {
+    var result = Object.create(null);
+    for (var i = 0; i < n; i++)
+        result = Object.create(result);
+    return result;
+}
+
+function updateChain(obj, depth, prop, value) {
+    // Walk down the proto chain |depth| iterations and set |prop| to |value|.
+    var cur = obj;
+    for (var i = 0; i < depth; i++)
+        cur = Object.getPrototypeOf(cur);
+
+    var desc = {value:value, writable:true, configurable:true, enumerable:true};
+    Object.defineProperty(cur, prop, desc);
+}
+
+print("/////////////////////////////////////////");
+print("// This is a generated file!");
+print("// See jit-tests/etc/generate-nosuchproperty-tests.js for the code");
+print("// that generated this code!");
+print("/////////////////////////////////////////");
+print("");
+print("/////////////////////////////////////////");
+print("// PRELUDE                             //");
+print("/////////////////////////////////////////");
+print("");
+print(createTower);
+print(updateChain);
+print("");
+print("/////////////////////////////////////////");
+print("// TEST CASES                          //");
+print("/////////////////////////////////////////");
+print("");
+for (var n = 0; n <= 10; n++) {
+    for (var d = 0; d <= n; d++) {
+        generateTestCase(n, d);
+    }
+}
+
+print("");
+print("/////////////////////////////////////////");
+print("// RUNNER                              //");
+print("/////////////////////////////////////////");
+print("");
+for (var i = 0; i < TEST_CASE_FUNCS.length; i++)
+    print(TEST_CASE_FUNCS[i] + "();");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/baseline/no-such-property-getprop.js
@@ -0,0 +1,1025 @@
+/////////////////////////////////////////
+// This is a generated file!
+// See jit-tests/etc/generate-nosuchproperty-tests.js for the code
+// that generated this code!
+/////////////////////////////////////////
+
+/////////////////////////////////////////
+// PRELUDE                             //
+/////////////////////////////////////////
+
+function createTower(n) {
+    var result = Object.create(null);
+    for (var i = 0; i < n; i++)
+        result = Object.create(result);
+    return result;
+}
+function updateChain(obj, depth, prop, value) {
+    // Walk down the proto chain |depth| iterations and set |prop| to |value|.
+    var cur = obj;
+    for (var i = 0; i < depth; i++)
+        cur = Object.getPrototypeOf(cur);
+
+    var desc = {value:value, writable:true, configurable:true, enumerable:true};
+    Object.defineProperty(cur, prop, desc);
+}
+
+/////////////////////////////////////////
+// TEST CASES                          //
+/////////////////////////////////////////
+
+//// Test chain of length 0 with late-property-addition at depth 0
+function runChain_0_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_0_0() {
+    var obj = createTower(0);
+    assertEq(runChain_0_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_0_0(obj), 900);
+}
+
+//// Test chain of length 1 with late-property-addition at depth 0
+function runChain_1_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_1_0() {
+    var obj = createTower(1);
+    assertEq(runChain_1_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_1_0(obj), 900);
+}
+
+//// Test chain of length 1 with late-property-addition at depth 1
+function runChain_1_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_1_1() {
+    var obj = createTower(1);
+    assertEq(runChain_1_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_1_1(obj), 900);
+}
+
+//// Test chain of length 2 with late-property-addition at depth 0
+function runChain_2_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_2_0() {
+    var obj = createTower(2);
+    assertEq(runChain_2_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_2_0(obj), 900);
+}
+
+//// Test chain of length 2 with late-property-addition at depth 1
+function runChain_2_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_2_1() {
+    var obj = createTower(2);
+    assertEq(runChain_2_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_2_1(obj), 900);
+}
+
+//// Test chain of length 2 with late-property-addition at depth 2
+function runChain_2_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_2_2() {
+    var obj = createTower(2);
+    assertEq(runChain_2_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_2_2(obj), 900);
+}
+
+//// Test chain of length 3 with late-property-addition at depth 0
+function runChain_3_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_3_0() {
+    var obj = createTower(3);
+    assertEq(runChain_3_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_3_0(obj), 900);
+}
+
+//// Test chain of length 3 with late-property-addition at depth 1
+function runChain_3_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_3_1() {
+    var obj = createTower(3);
+    assertEq(runChain_3_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_3_1(obj), 900);
+}
+
+//// Test chain of length 3 with late-property-addition at depth 2
+function runChain_3_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_3_2() {
+    var obj = createTower(3);
+    assertEq(runChain_3_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_3_2(obj), 900);
+}
+
+//// Test chain of length 3 with late-property-addition at depth 3
+function runChain_3_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_3_3() {
+    var obj = createTower(3);
+    assertEq(runChain_3_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_3_3(obj), 900);
+}
+
+//// Test chain of length 4 with late-property-addition at depth 0
+function runChain_4_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_4_0() {
+    var obj = createTower(4);
+    assertEq(runChain_4_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_4_0(obj), 900);
+}
+
+//// Test chain of length 4 with late-property-addition at depth 1
+function runChain_4_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_4_1() {
+    var obj = createTower(4);
+    assertEq(runChain_4_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_4_1(obj), 900);
+}
+
+//// Test chain of length 4 with late-property-addition at depth 2
+function runChain_4_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_4_2() {
+    var obj = createTower(4);
+    assertEq(runChain_4_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_4_2(obj), 900);
+}
+
+//// Test chain of length 4 with late-property-addition at depth 3
+function runChain_4_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_4_3() {
+    var obj = createTower(4);
+    assertEq(runChain_4_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_4_3(obj), 900);
+}
+
+//// Test chain of length 4 with late-property-addition at depth 4
+function runChain_4_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_4_4() {
+    var obj = createTower(4);
+    assertEq(runChain_4_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_4_4(obj), 900);
+}
+
+//// Test chain of length 5 with late-property-addition at depth 0
+function runChain_5_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_5_0() {
+    var obj = createTower(5);
+    assertEq(runChain_5_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_5_0(obj), 900);
+}
+
+//// Test chain of length 5 with late-property-addition at depth 1
+function runChain_5_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_5_1() {
+    var obj = createTower(5);
+    assertEq(runChain_5_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_5_1(obj), 900);
+}
+
+//// Test chain of length 5 with late-property-addition at depth 2
+function runChain_5_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_5_2() {
+    var obj = createTower(5);
+    assertEq(runChain_5_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_5_2(obj), 900);
+}
+
+//// Test chain of length 5 with late-property-addition at depth 3
+function runChain_5_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_5_3() {
+    var obj = createTower(5);
+    assertEq(runChain_5_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_5_3(obj), 900);
+}
+
+//// Test chain of length 5 with late-property-addition at depth 4
+function runChain_5_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_5_4() {
+    var obj = createTower(5);
+    assertEq(runChain_5_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_5_4(obj), 900);
+}
+
+//// Test chain of length 5 with late-property-addition at depth 5
+function runChain_5_5(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_5_5() {
+    var obj = createTower(5);
+    assertEq(runChain_5_5(obj), NaN);
+    updateChain(obj, 5, 'foo', 9);
+    assertEq(runChain_5_5(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 0
+function runChain_6_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_0() {
+    var obj = createTower(6);
+    assertEq(runChain_6_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_6_0(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 1
+function runChain_6_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_1() {
+    var obj = createTower(6);
+    assertEq(runChain_6_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_6_1(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 2
+function runChain_6_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_2() {
+    var obj = createTower(6);
+    assertEq(runChain_6_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_6_2(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 3
+function runChain_6_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_3() {
+    var obj = createTower(6);
+    assertEq(runChain_6_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_6_3(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 4
+function runChain_6_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_4() {
+    var obj = createTower(6);
+    assertEq(runChain_6_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_6_4(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 5
+function runChain_6_5(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_5() {
+    var obj = createTower(6);
+    assertEq(runChain_6_5(obj), NaN);
+    updateChain(obj, 5, 'foo', 9);
+    assertEq(runChain_6_5(obj), 900);
+}
+
+//// Test chain of length 6 with late-property-addition at depth 6
+function runChain_6_6(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_6_6() {
+    var obj = createTower(6);
+    assertEq(runChain_6_6(obj), NaN);
+    updateChain(obj, 6, 'foo', 9);
+    assertEq(runChain_6_6(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 0
+function runChain_7_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_0() {
+    var obj = createTower(7);
+    assertEq(runChain_7_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_7_0(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 1
+function runChain_7_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_1() {
+    var obj = createTower(7);
+    assertEq(runChain_7_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_7_1(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 2
+function runChain_7_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_2() {
+    var obj = createTower(7);
+    assertEq(runChain_7_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_7_2(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 3
+function runChain_7_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_3() {
+    var obj = createTower(7);
+    assertEq(runChain_7_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_7_3(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 4
+function runChain_7_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_4() {
+    var obj = createTower(7);
+    assertEq(runChain_7_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_7_4(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 5
+function runChain_7_5(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_5() {
+    var obj = createTower(7);
+    assertEq(runChain_7_5(obj), NaN);
+    updateChain(obj, 5, 'foo', 9);
+    assertEq(runChain_7_5(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 6
+function runChain_7_6(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_6() {
+    var obj = createTower(7);
+    assertEq(runChain_7_6(obj), NaN);
+    updateChain(obj, 6, 'foo', 9);
+    assertEq(runChain_7_6(obj), 900);
+}
+
+//// Test chain of length 7 with late-property-addition at depth 7
+function runChain_7_7(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_7_7() {
+    var obj = createTower(7);
+    assertEq(runChain_7_7(obj), NaN);
+    updateChain(obj, 7, 'foo', 9);
+    assertEq(runChain_7_7(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 0
+function runChain_8_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_0() {
+    var obj = createTower(8);
+    assertEq(runChain_8_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_8_0(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 1
+function runChain_8_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_1() {
+    var obj = createTower(8);
+    assertEq(runChain_8_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_8_1(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 2
+function runChain_8_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_2() {
+    var obj = createTower(8);
+    assertEq(runChain_8_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_8_2(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 3
+function runChain_8_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_3() {
+    var obj = createTower(8);
+    assertEq(runChain_8_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_8_3(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 4
+function runChain_8_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_4() {
+    var obj = createTower(8);
+    assertEq(runChain_8_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_8_4(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 5
+function runChain_8_5(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_5() {
+    var obj = createTower(8);
+    assertEq(runChain_8_5(obj), NaN);
+    updateChain(obj, 5, 'foo', 9);
+    assertEq(runChain_8_5(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 6
+function runChain_8_6(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_6() {
+    var obj = createTower(8);
+    assertEq(runChain_8_6(obj), NaN);
+    updateChain(obj, 6, 'foo', 9);
+    assertEq(runChain_8_6(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 7
+function runChain_8_7(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_7() {
+    var obj = createTower(8);
+    assertEq(runChain_8_7(obj), NaN);
+    updateChain(obj, 7, 'foo', 9);
+    assertEq(runChain_8_7(obj), 900);
+}
+
+//// Test chain of length 8 with late-property-addition at depth 8
+function runChain_8_8(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_8_8() {
+    var obj = createTower(8);
+    assertEq(runChain_8_8(obj), NaN);
+    updateChain(obj, 8, 'foo', 9);
+    assertEq(runChain_8_8(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 0
+function runChain_9_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_0() {
+    var obj = createTower(9);
+    assertEq(runChain_9_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_9_0(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 1
+function runChain_9_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_1() {
+    var obj = createTower(9);
+    assertEq(runChain_9_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_9_1(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 2
+function runChain_9_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_2() {
+    var obj = createTower(9);
+    assertEq(runChain_9_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_9_2(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 3
+function runChain_9_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_3() {
+    var obj = createTower(9);
+    assertEq(runChain_9_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_9_3(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 4
+function runChain_9_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_4() {
+    var obj = createTower(9);
+    assertEq(runChain_9_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_9_4(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 5
+function runChain_9_5(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_5() {
+    var obj = createTower(9);
+    assertEq(runChain_9_5(obj), NaN);
+    updateChain(obj, 5, 'foo', 9);
+    assertEq(runChain_9_5(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 6
+function runChain_9_6(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_6() {
+    var obj = createTower(9);
+    assertEq(runChain_9_6(obj), NaN);
+    updateChain(obj, 6, 'foo', 9);
+    assertEq(runChain_9_6(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 7
+function runChain_9_7(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_7() {
+    var obj = createTower(9);
+    assertEq(runChain_9_7(obj), NaN);
+    updateChain(obj, 7, 'foo', 9);
+    assertEq(runChain_9_7(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 8
+function runChain_9_8(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_8() {
+    var obj = createTower(9);
+    assertEq(runChain_9_8(obj), NaN);
+    updateChain(obj, 8, 'foo', 9);
+    assertEq(runChain_9_8(obj), 900);
+}
+
+//// Test chain of length 9 with late-property-addition at depth 9
+function runChain_9_9(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_9_9() {
+    var obj = createTower(9);
+    assertEq(runChain_9_9(obj), NaN);
+    updateChain(obj, 9, 'foo', 9);
+    assertEq(runChain_9_9(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 0
+function runChain_10_0(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_0() {
+    var obj = createTower(10);
+    assertEq(runChain_10_0(obj), NaN);
+    updateChain(obj, 0, 'foo', 9);
+    assertEq(runChain_10_0(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 1
+function runChain_10_1(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_1() {
+    var obj = createTower(10);
+    assertEq(runChain_10_1(obj), NaN);
+    updateChain(obj, 1, 'foo', 9);
+    assertEq(runChain_10_1(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 2
+function runChain_10_2(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_2() {
+    var obj = createTower(10);
+    assertEq(runChain_10_2(obj), NaN);
+    updateChain(obj, 2, 'foo', 9);
+    assertEq(runChain_10_2(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 3
+function runChain_10_3(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_3() {
+    var obj = createTower(10);
+    assertEq(runChain_10_3(obj), NaN);
+    updateChain(obj, 3, 'foo', 9);
+    assertEq(runChain_10_3(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 4
+function runChain_10_4(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_4() {
+    var obj = createTower(10);
+    assertEq(runChain_10_4(obj), NaN);
+    updateChain(obj, 4, 'foo', 9);
+    assertEq(runChain_10_4(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 5
+function runChain_10_5(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_5() {
+    var obj = createTower(10);
+    assertEq(runChain_10_5(obj), NaN);
+    updateChain(obj, 5, 'foo', 9);
+    assertEq(runChain_10_5(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 6
+function runChain_10_6(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_6() {
+    var obj = createTower(10);
+    assertEq(runChain_10_6(obj), NaN);
+    updateChain(obj, 6, 'foo', 9);
+    assertEq(runChain_10_6(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 7
+function runChain_10_7(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_7() {
+    var obj = createTower(10);
+    assertEq(runChain_10_7(obj), NaN);
+    updateChain(obj, 7, 'foo', 9);
+    assertEq(runChain_10_7(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 8
+function runChain_10_8(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_8() {
+    var obj = createTower(10);
+    assertEq(runChain_10_8(obj), NaN);
+    updateChain(obj, 8, 'foo', 9);
+    assertEq(runChain_10_8(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 9
+function runChain_10_9(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_9() {
+    var obj = createTower(10);
+    assertEq(runChain_10_9(obj), NaN);
+    updateChain(obj, 9, 'foo', 9);
+    assertEq(runChain_10_9(obj), 900);
+}
+
+//// Test chain of length 10 with late-property-addition at depth 10
+function runChain_10_10(obj) {
+    var sum = 0;
+    for (var i = 0; i < 100; i++)
+        sum += obj.foo;
+    return sum;
+}
+function testChain_10_10() {
+    var obj = createTower(10);
+    assertEq(runChain_10_10(obj), NaN);
+    updateChain(obj, 10, 'foo', 9);
+    assertEq(runChain_10_10(obj), 900);
+}
+
+
+/////////////////////////////////////////
+// RUNNER                              //
+/////////////////////////////////////////
+
+testChain_0_0();
+testChain_1_0();
+testChain_1_1();
+testChain_2_0();
+testChain_2_1();
+testChain_2_2();
+testChain_3_0();
+testChain_3_1();
+testChain_3_2();
+testChain_3_3();
+testChain_4_0();
+testChain_4_1();
+testChain_4_2();
+testChain_4_3();
+testChain_4_4();
+testChain_5_0();
+testChain_5_1();
+testChain_5_2();
+testChain_5_3();
+testChain_5_4();
+testChain_5_5();
+testChain_6_0();
+testChain_6_1();
+testChain_6_2();
+testChain_6_3();
+testChain_6_4();
+testChain_6_5();
+testChain_6_6();
+testChain_7_0();
+testChain_7_1();
+testChain_7_2();
+testChain_7_3();
+testChain_7_4();
+testChain_7_5();
+testChain_7_6();
+testChain_7_7();
+testChain_8_0();
+testChain_8_1();
+testChain_8_2();
+testChain_8_3();
+testChain_8_4();
+testChain_8_5();
+testChain_8_6();
+testChain_8_7();
+testChain_8_8();
+testChain_9_0();
+testChain_9_1();
+testChain_9_2();
+testChain_9_3();
+testChain_9_4();
+testChain_9_5();
+testChain_9_6();
+testChain_9_7();
+testChain_9_8();
+testChain_9_9();
+testChain_10_0();
+testChain_10_1();
+testChain_10_2();
+testChain_10_3();
+testChain_10_4();
+testChain_10_5();
+testChain_10_6();
+testChain_10_7();
+testChain_10_8();
+testChain_10_9();
+testChain_10_10();
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -330,16 +330,33 @@ ICStub::trace(JSTracer *trc)
       }
       case ICStub::GetProp_NativePrototype: {
         ICGetProp_NativePrototype *propStub = toGetProp_NativePrototype();
         MarkShape(trc, &propStub->shape(), "baseline-getpropnativeproto-stub-shape");
         MarkObject(trc, &propStub->holder(), "baseline-getpropnativeproto-stub-holder");
         MarkShape(trc, &propStub->holderShape(), "baseline-getpropnativeproto-stub-holdershape");
         break;
       }
+      case ICStub::GetProp_NativeDoesNotExist: {
+        ICGetProp_NativeDoesNotExist *propStub = toGetProp_NativeDoesNotExist();
+        JS_STATIC_ASSERT(ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8);
+        switch (propStub->protoChainDepth()) {
+          case 0: propStub->toImpl<0>()->traceShapes(trc); break;
+          case 1: propStub->toImpl<1>()->traceShapes(trc); break;
+          case 2: propStub->toImpl<2>()->traceShapes(trc); break;
+          case 3: propStub->toImpl<3>()->traceShapes(trc); break;
+          case 4: propStub->toImpl<4>()->traceShapes(trc); break;
+          case 5: propStub->toImpl<5>()->traceShapes(trc); break;
+          case 6: propStub->toImpl<6>()->traceShapes(trc); break;
+          case 7: propStub->toImpl<7>()->traceShapes(trc); break;
+          case 8: propStub->toImpl<8>()->traceShapes(trc); break;
+          default: MOZ_ASSUME_UNREACHABLE("Invalid proto stub.");
+        }
+        break;
+      }
       case ICStub::GetProp_CallDOMProxyNative:
       case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
         ICGetPropCallDOMProxyNativeStub *propStub;
         if (kind() ==  ICStub::GetProp_CallDOMProxyNative)
             propStub = toGetProp_CallDOMProxyNative();
         else
             propStub = toGetProp_CallDOMProxyWithGenerationNative();
         MarkShape(trc, &propStub->shape(), "baseline-getproplistbasenative-stub-shape");
@@ -3336,16 +3353,45 @@ EffectlesslyLookupProperty(JSContext *cx
         shape.set(checkObj->nativeLookup(cx, NameToId(name)));
         if (shape)
             holder.set(checkObj);
     }
     return true;
 }
 
 static bool
+CheckHasNoSuchProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                       MutableHandleObject lastProto, size_t *protoChainDepthOut)
+{
+    MOZ_ASSERT(protoChainDepthOut != nullptr);
+
+    size_t depth = 0;
+    RootedObject curObj(cx, obj);
+    while (curObj) {
+        if (!curObj->isNative())
+            return false;
+
+        Shape *shape = curObj->nativeLookup(cx, NameToId(name));
+        if (shape)
+            return false;
+
+        JSObject *proto = curObj->getTaggedProto().toObjectOrNull();
+        if (!proto)
+            break;
+
+        curObj = proto;
+        depth++;
+    }
+
+    lastProto.set(curObj);
+    *protoChainDepthOut = depth;
+    return true;
+}
+
+static bool
 IsCacheableProtoChain(JSObject *obj, JSObject *holder, bool isDOMProxy=false)
 {
     JS_ASSERT_IF(isDOMProxy, IsCacheableDOMProxy(obj));
     JS_ASSERT_IF(!isDOMProxy, obj->isNative());
 
     // Don't handle objects which require a prototype guard. This should
     // be uncommon so handling it is likely not worth the complexity.
     if (obj->hasUncacheableProto())
@@ -6331,16 +6377,58 @@ TryAttachPrimitiveGetPropStub(JSContext 
         return false;
 
     stub->addNewStub(newStub);
     *attached = true;
     return true;
 }
 
 static bool
+TryAttachNativeDoesNotExistStub(JSContext *cx, HandleScript script, jsbytecode *pc,
+                                ICGetProp_Fallback *stub, HandlePropertyName name,
+                                HandleValue val, bool *attached)
+{
+    MOZ_ASSERT(!*attached);
+
+    if (!val.isObject())
+        return true;
+
+    RootedObject obj(cx, &val.toObject());
+
+    // Don't attach stubs for CALLPROP since those need NoSuchMethod handling.
+    if (JSOp(*pc) == JSOP_CALLPROP)
+        return true;
+
+    // Check if does-not-exist can be confirmed on property.
+    RootedObject lastProto(cx);
+    size_t protoChainDepth = SIZE_MAX;
+    if (!CheckHasNoSuchProperty(cx, obj, name, &lastProto, &protoChainDepth))
+        return true;
+    MOZ_ASSERT(protoChainDepth < SIZE_MAX);
+
+    if (protoChainDepth > ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH)
+        return true;
+
+    ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
+    RootedShape objShape(cx, obj->lastProperty());
+    RootedShape lastShape(cx, lastProto->lastProperty());
+
+    // Confirmed no-such-property.  Add stub.
+    IonSpew(IonSpew_BaselineIC, "  Generating GetProp_NativeDoesNotExist stub");
+    ICGetPropNativeDoesNotExistCompiler compiler(cx, monitorStub, obj, protoChainDepth);
+    ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
+    if (!newStub)
+        return false;
+
+    stub->addNewStub(newStub);
+    *attached = true;
+    return true;
+}
+
+static bool
 DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_,
                   MutableHandleValue val, MutableHandleValue res)
 {
     // This fallback stub may trigger debug mode toggling.
     DebugModeOSRVolatileStub<ICGetProp_Fallback *> stub(frame, stub_);
 
     jsbytecode *pc = stub->icEntry()->pc(frame->script());
     JSOp op = JSOp(*pc);
@@ -6418,16 +6506,24 @@ DoGetPropFallback(JSContext *cx, Baselin
 
     if (val.isString() || val.isNumber() || val.isBoolean()) {
         if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
             return false;
         if (attached)
             return true;
     }
 
+    if (res.isUndefined()) {
+        // Try attaching property-not-found optimized stub for undefined results.
+        if (!TryAttachNativeDoesNotExistStub(cx, script, pc, stub, name, val, &attached))
+            return false;
+        if (attached)
+            return true;
+    }
+
     JS_ASSERT(!attached);
     stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoGetPropFallbackFn)(JSContext *, BaselineFrame *, ICGetProp_Fallback *,
                                     MutableHandleValue, MutableHandleValue);
@@ -6675,16 +6771,97 @@ ICGetPropNativeCompiler::generateStubCod
     EmitEnterTypeMonitorIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
+ICStub *
+ICGetPropNativeDoesNotExistCompiler::getStub(ICStubSpace *space)
+{
+    AutoShapeVector shapes(cx);
+    if (!shapes.append(obj_->lastProperty()))
+        return nullptr;
+
+    if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
+        return nullptr;
+
+    JS_STATIC_ASSERT(ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8);
+
+    ICStub *stub = nullptr;
+    switch(protoChainDepth_) {
+      case 0: stub = getStubSpecific<0>(space, &shapes); break;
+      case 1: stub = getStubSpecific<1>(space, &shapes); break;
+      case 2: stub = getStubSpecific<2>(space, &shapes); break;
+      case 3: stub = getStubSpecific<3>(space, &shapes); break;
+      case 4: stub = getStubSpecific<4>(space, &shapes); break;
+      case 5: stub = getStubSpecific<5>(space, &shapes); break;
+      case 6: stub = getStubSpecific<6>(space, &shapes); break;
+      case 7: stub = getStubSpecific<7>(space, &shapes); break;
+      case 8: stub = getStubSpecific<8>(space, &shapes); break;
+      default: MOZ_ASSUME_UNREACHABLE("ProtoChainDepth too high.");
+    }
+    if (!stub)
+        return nullptr;
+    return stub;
+}
+
+bool
+ICGetPropNativeDoesNotExistCompiler::generateStubCode(MacroAssembler &masm)
+{
+    Label failure;
+
+    GeneralRegisterSet regs(availableGeneralRegs(1));
+    Register scratch = regs.takeAny();
+
+#ifdef DEBUG
+    // Ensure that protoChainDepth_ matches the protoChainDepth stored on the stub.
+    {
+        Label ok;
+        masm.load16ZeroExtend(Address(BaselineStubReg, ICStub::offsetOfExtra()), scratch);
+        masm.branch32(Assembler::Equal, scratch, Imm32(protoChainDepth_), &ok);
+        masm.assumeUnreachable("Non-matching proto chain depth on stub.");
+        masm.bind(&ok);
+    }
+#endif // DEBUG
+
+    // Guard input is an object.
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+
+    // Unbox and guard against old shape.
+    Register objReg = masm.extractObject(R0, ExtractTemp0);
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_NativeDoesNotExist::offsetOfShape(0)),
+                 scratch);
+    masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
+
+    Register protoReg = regs.takeAny();
+    // Check the proto chain.
+    for (size_t i = 0; i < protoChainDepth_; i++) {
+        masm.loadObjProto(i == 0 ? objReg : protoReg, protoReg);
+        masm.branchTestPtr(Assembler::Zero, protoReg, protoReg, &failure);
+        size_t shapeOffset = ICGetProp_NativeDoesNotExistImpl<0>::offsetOfShape(i + 1);
+        masm.loadPtr(Address(BaselineStubReg, shapeOffset), scratch);
+        masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratch, &failure);
+    }
+
+    // Shape and type checks succeeded, ok to proceed.
+    masm.moveValue(UndefinedValue(), R0);
+
+    // Normally for this op, the result would have to be monitored by TI.
+    // However, since this stub ALWAYS returns UndefinedValue(), and we can be sure
+    // that undefined is already registered with the type-set, this can be avoided.
+    EmitReturnFromIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
 bool
 ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
     Label failureLeaveStubFrame;
     GeneralRegisterSet regs(availableGeneralRegs(1));
     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
 
@@ -10120,16 +10297,53 @@ ICGetProp_NativePrototype::Clone(JSConte
 {
     RootedShape shape(cx, other.shape());
     RootedObject holder(cx, other.holder_);
     RootedShape holderShape(cx, other.holderShape_);
     return New(space, other.jitCode(), firstMonitorStub, shape, other.offset(),
                holder, holderShape);
 }
 
+ICGetProp_NativeDoesNotExist::ICGetProp_NativeDoesNotExist(
+        JitCode *stubCode, ICStub *firstMonitorStub, size_t protoChainDepth)
+  : ICMonitoredStub(GetProp_NativeDoesNotExist, stubCode, firstMonitorStub)
+{
+    MOZ_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH);
+    extra_ = protoChainDepth;
+}
+
+/* static */ size_t
+ICGetProp_NativeDoesNotExist::offsetOfShape(size_t idx)
+{
+    MOZ_ASSERT(ICGetProp_NativeDoesNotExistImpl<0>::offsetOfShape(idx) ==
+               ICGetProp_NativeDoesNotExistImpl<
+                    ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH>::offsetOfShape(idx));
+    return ICGetProp_NativeDoesNotExistImpl<0>::offsetOfShape(idx);
+}
+
+template <size_t ProtoChainDepth>
+ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth>::ICGetProp_NativeDoesNotExistImpl(
+        JitCode *stubCode, ICStub *firstMonitorStub, const AutoShapeVector *shapes)
+  : ICGetProp_NativeDoesNotExist(stubCode, firstMonitorStub, ProtoChainDepth)
+{
+    MOZ_ASSERT(shapes->length() == NumShapes);
+    for (size_t i = 0; i < NumShapes; i++)
+        shapes_[i].init((*shapes)[i]);
+}
+
+ICGetPropNativeDoesNotExistCompiler::ICGetPropNativeDoesNotExistCompiler(
+        JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, size_t protoChainDepth)
+  : ICStubCompiler(cx, ICStub::GetProp_NativeDoesNotExist),
+    firstMonitorStub_(firstMonitorStub),
+    obj_(cx, obj),
+    protoChainDepth_(protoChainDepth)
+{
+    MOZ_ASSERT(protoChainDepth_ <= ICGetProp_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH);
+}
+
 ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
                                          HandleObject holder, HandleShape holderShape, HandleFunction getter,
                                          uint32_t pcOffset)
   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
     holder_(holder),
     holderShape_(holderShape),
     getter_(getter),
     pcOffset_(pcOffset)
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -409,16 +409,17 @@ class ICEntry
     _(GetIntrinsic_Fallback)    \
     _(GetIntrinsic_Constant)    \
                                 \
     _(GetProp_Fallback)         \
     _(GetProp_ArrayLength)      \
     _(GetProp_Primitive)        \
     _(GetProp_StringLength)     \
     _(GetProp_Native)           \
+    _(GetProp_NativeDoesNotExist) \
     _(GetProp_NativePrototype)  \
     _(GetProp_CallScripted)     \
     _(GetProp_CallNative)       \
     _(GetProp_CallNativePrototype)\
     _(GetProp_CallDOMProxyNative)\
     _(GetProp_CallDOMProxyWithGenerationNative)\
     _(GetProp_DOMProxyShadowed) \
     _(GetProp_ArgumentsLength)  \
@@ -4407,16 +4408,114 @@ class ICGetPropNativeCompiler : public I
         JS_ASSERT(obj_ != holder_);
         JS_ASSERT(kind == ICStub::GetProp_NativePrototype);
         RootedShape holderShape(cx, holder_->lastProperty());
         return ICGetProp_NativePrototype::New(space, getStubCode(), firstMonitorStub_, shape,
                                               offset_, holder_, holderShape);
     }
 };
 
+template <size_t ProtoChainDepth> class ICGetProp_NativeDoesNotExistImpl;
+
+class ICGetProp_NativeDoesNotExist : public ICMonitoredStub
+{
+    friend class ICStubSpace;
+  public:
+    static const size_t MAX_PROTO_CHAIN_DEPTH = 8;
+
+  protected:
+    ICGetProp_NativeDoesNotExist(JitCode *stubCode, ICStub *firstMonitorStub,
+                                 size_t protoChainDepth);
+
+  public:
+    static inline ICGetProp_NativeDoesNotExist *New(ICStubSpace *space, JitCode *code,
+                                                    ICStub *firstMonitorStub,
+                                                    size_t protoChainDepth)
+    {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICGetProp_NativeDoesNotExist>(code, firstMonitorStub,
+                                                             protoChainDepth);
+    }
+
+    size_t protoChainDepth() const {
+        MOZ_ASSERT(extra_ <= MAX_PROTO_CHAIN_DEPTH);
+        return extra_;
+    }
+
+    template <size_t ProtoChainDepth>
+    ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth> *toImpl() {
+        MOZ_ASSERT(ProtoChainDepth == protoChainDepth());
+        return static_cast<ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth> *>(this);
+    }
+
+    static size_t offsetOfShape(size_t idx);
+};
+
+template <size_t ProtoChainDepth>
+class ICGetProp_NativeDoesNotExistImpl : public ICGetProp_NativeDoesNotExist
+{
+    friend class ICStubSpace;
+  public:
+    static const size_t MAX_PROTO_CHAIN_DEPTH = 8;
+    static const size_t NumShapes = ProtoChainDepth + 1;
+
+  private:
+    mozilla::Array<HeapPtrShape, NumShapes> shapes_;
+
+    ICGetProp_NativeDoesNotExistImpl(JitCode *stubCode, ICStub *firstMonitorStub,
+                                     const AutoShapeVector *shapes);
+
+  public:
+    static inline ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth> *New(
+        ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
+        const AutoShapeVector *shapes)
+    {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth>>(
+                    code, firstMonitorStub, shapes);
+    }
+
+    void traceShapes(JSTracer *trc) {
+        for (size_t i = 0; i < NumShapes; i++)
+            MarkShape(trc, &shapes_[i], "baseline-getpropnativedoesnotexist-stub-shape");
+    }
+
+    static size_t offsetOfShape(size_t idx) {
+        return offsetof(ICGetProp_NativeDoesNotExistImpl, shapes_) + (idx * sizeof(HeapPtrShape));
+    }
+};
+
+class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler
+{
+    ICStub *firstMonitorStub_;
+    RootedObject obj_;
+    size_t protoChainDepth_;
+
+  protected:
+    virtual int32_t getKey() const {
+        return static_cast<int32_t>(kind) | (static_cast<int32_t>(protoChainDepth_) << 16);
+    }
+
+    bool generateStubCode(MacroAssembler &masm);
+
+  public:
+    ICGetPropNativeDoesNotExistCompiler(JSContext *cx, ICStub *firstMonitorStub,
+                                        HandleObject obj, size_t protoChainDepth);
+
+    template <size_t ProtoChainDepth>
+    ICStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes) {
+        return ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth>::New(space, getStubCode(),
+                                                                      firstMonitorStub_, shapes);
+    }
+
+    ICStub *getStub(ICStubSpace *space);
+};
+
 class ICGetPropCallGetter : public ICMonitoredStub
 {
     friend class ICStubSpace;
 
   protected:
     // We don't strictly need this for own property getters, but we need it to do
     // Ion optimizations, so we should keep it around.
     HeapPtrObject holder_;
@@ -5150,17 +5249,18 @@ class ICSetProp_NativeAddImpl : public I
             MarkShape(trc, &shapes_[i], "baseline-setpropnativeadd-stub-shape");
     }
 
     static size_t offsetOfShape(size_t idx) {
         return offsetof(ICSetProp_NativeAddImpl, shapes_) + (idx * sizeof(HeapPtrShape));
     }
 };
 
-class ICSetPropNativeAddCompiler : public ICStubCompiler {
+class ICSetPropNativeAddCompiler : public ICStubCompiler
+{
     RootedObject obj_;
     RootedShape oldShape_;
     size_t protoChainDepth_;
     bool isFixedSlot_;
     uint32_t offset_;
 
   protected:
     virtual int32_t getKey() const {