promise-constructor.js 5.46 KB
Newer Older
1 2 3 4
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
// Flags: --allow-natives-syntax --ignore-unhandled-promises
6 7 8 9 10 11 12 13 14 15 16 17 18 19

// We have to patch mjsunit because normal assertion failures just throw
// exceptions which are swallowed in a then clause.
failWithMessage = (msg) => %AbortJS(msg);

// Don't crash.
(function() {
  function foo() {
    let resolve, reject, promise;
    promise = new Promise((a, b) => { resolve = a; reject = b; });

    return {resolve, reject, promise};
  }

20
  %PrepareFunctionForOptimization(foo);
21 22 23 24 25 26
  foo();
  foo();
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();

27 28 29 30 31 32
// Check that when executor is non-callable, the constructor throws.
(function() {
  function foo() {
    return new Promise(1);
  }

33
  %PrepareFunctionForOptimization(foo);
34 35 36 37 38 39 40 41 42 43 44 45
  assertThrows(foo, TypeError);
  assertThrows(foo, TypeError);
  %OptimizeFunctionOnNextCall(foo);
  assertThrows(foo, TypeError);
})();

// Check that when the promise constructor throws because the executor is
// non-callable, the stack contains 'new Promise'.
(function() {
  function foo() {
    return new Promise(1);
  }
46

47
  %PrepareFunctionForOptimization(foo);
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
  let threw;
  try {
    threw = false;
    foo();
  } catch (e) {
    threw = true;
    assertContains('new Promise', e.stack);
  } finally {
    assertTrue(threw);
  }
  try {
    threw = false;
    foo();
  } catch (e) {
    threw = true;
    assertContains('new Promise', e.stack);
  } finally {
    assertTrue(threw);
  }

  %OptimizeFunctionOnNextCall(foo);
  try {
    threw = false;
    foo();
  } catch (e) {
    threw = true;
74
    assertContains('new Promise', e.stack);
75 76 77 78 79 80
  } finally {
    assertTrue(threw);
  }
})();

// Check that when executor throws, the promise is rejected.
81 82 83 84
(function() {
  function foo() {
    return new Promise((a, b) => { throw new Error(); });
  }
85
  %PrepareFunctionForOptimization(foo);
86 87

  function bar(i) {
88 89 90 91 92 93 94
    let error = null;
    foo().then(_ => error = 1, e => error = e);
    setTimeout(_ => assertInstanceof(error, Error));
    if (i == 1) %OptimizeFunctionOnNextCall(foo);
    if (i > 0) setTimeout(bar.bind(null, i - 1));
    }
  bar(3);
95 96
})();

97 98 99
// Check that when executor causes lazy deoptimization of the inlined
// constructor, we return the promise value and not the return value of the
// executor function itself.
100 101 102 103 104 105 106 107 108
(function() {
  function foo() {
    let p;
    try {
      p = new Promise((a, b) => { %DeoptimizeFunction(foo); });
    } catch (e) {
      // Nothing should throw
      assertUnreachable();
    }
109
    assertInstanceof(p, Promise);
110 111
  }

112
  %PrepareFunctionForOptimization(foo);
113 114 115 116 117 118
  foo();
  foo();
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();

119 120
// The same as above, except that the executor function also creates a promise
// and both executor functions cause a lazy deopt of the calling function.
121
(function() {
122 123 124 125
  function executor(a, b) {
    %DeoptimizeFunction(foo);
    let p = new Promise((a, b) => { %DeoptimizeFunction(executor); });
  }
126 127 128
  function foo() {
    let p;
    try {
129 130 131 132 133 134 135 136
      p = new Promise(executor);
    } catch (e) {
      // Nothing should throw
      assertUnreachable();
    }
    assertInstanceof(p, Promise);
  }

137
  %PrepareFunctionForOptimization(foo);
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  foo();
  foo();
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();

// Check that when the executor causes lazy deoptimization of the inlined
// constructor, and then throws, the deopt continuation catches and then calls
// the reject function instead of propagating the exception.
(function() {
  function foo() {
    let p;
    try {
      p = new Promise((a, b) => {
        %DeoptimizeFunction(foo);
        throw new Error();
      });
155 156 157
    } catch (e) {
      // The promise constructor should catch the exception and reject the
      // promise instead.
158
      assertUnreachable();
159
    }
160
    assertInstanceof(p, Promise);
161 162
  }

163
  %PrepareFunctionForOptimization(foo);
164 165 166 167 168 169
  foo();
  foo();
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

// Check that when the promise constructor is marked for lazy deoptimization
// from below, but not immediatelly deoptimized, and then throws, the deopt continuation
// catches and calls the reject function instead of propagating the exception.
(function() {
  function foo() {
    let p;
    try {
      p = new Promise((resolve, reject) => { bar(); resolve()});
    } catch (e) {
       // The promise constructor should catch the exception and reject the
      // promise instead.
      assertUnreachable();
    }
    assertInstanceof(p, Promise);
  }

  function bar() {
    %DeoptimizeFunction(foo);
    throw new Error();
  }
  %NeverOptimizeFunction(bar);

193
  %PrepareFunctionForOptimization(foo);
194 195 196 197 198 199
  foo();
  foo();
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();

200 201 202 203 204 205 206 207 208 209
// Test when the executor is not inlined.
(function() {
  let resolve, reject, promise;
  function bar(a, b) {
    resolve = a; reject = b;
    throw new Error();
  }
  function foo() {
    promise = new Promise(bar);
  }
210
  %PrepareFunctionForOptimization(foo);
211 212 213 214 215 216 217 218 219 220 221 222 223
  foo();
  foo();
  %NeverOptimizeFunction(bar);
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();

// Test that the stack trace contains 'new Promise'
(function() {
  let resolve, reject, promise;
  function bar(a, b) {
    resolve = a; reject = b;
    let stack = new Error().stack;
224
    assertContains("new Promise", stack);
225 226 227 228 229
    throw new Error();
  }
  function foo() {
    promise = new Promise(bar);
  }
230
  %PrepareFunctionForOptimization(foo);
231 232 233 234 235
  foo();
  foo();
  %OptimizeFunctionOnNextCall(foo);
  foo();
})();