OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/isolate.h" | 5 #include "src/isolate.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 | 8 |
9 #include <fstream> // NOLINT(readability/streams) | 9 #include <fstream> // NOLINT(readability/streams) |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 1790 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1801 void Isolate::PopPromise() { | 1801 void Isolate::PopPromise() { |
1802 ThreadLocalTop* tltop = thread_local_top(); | 1802 ThreadLocalTop* tltop = thread_local_top(); |
1803 if (tltop->promise_on_stack_ == NULL) return; | 1803 if (tltop->promise_on_stack_ == NULL) return; |
1804 PromiseOnStack* prev = tltop->promise_on_stack_->prev(); | 1804 PromiseOnStack* prev = tltop->promise_on_stack_->prev(); |
1805 Handle<Object> global_promise = tltop->promise_on_stack_->promise(); | 1805 Handle<Object> global_promise = tltop->promise_on_stack_->promise(); |
1806 delete tltop->promise_on_stack_; | 1806 delete tltop->promise_on_stack_; |
1807 tltop->promise_on_stack_ = prev; | 1807 tltop->promise_on_stack_ = prev; |
1808 global_handles()->Destroy(global_promise.location()); | 1808 global_handles()->Destroy(global_promise.location()); |
1809 } | 1809 } |
1810 | 1810 |
| 1811 namespace { |
| 1812 bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate, |
| 1813 Handle<JSPromise> promise); |
| 1814 |
| 1815 bool PromiseHandlerCheck(Isolate* isolate, Handle<JSReceiver> handler, |
| 1816 Handle<JSObject> deferred) { |
| 1817 // Recurse to the forwarding Promise, if any. This may be due to |
| 1818 // - await reaction forwarding to the throwaway Promise, which has |
| 1819 // a dependency edge to the outer Promise. |
| 1820 // - PromiseIdResolveHandler forwarding to the output of .then |
| 1821 // - Promise.all/Promise.race forwarding to a throwaway Promise, which |
| 1822 // has a dependency edge to the generated outer Promise. |
| 1823 Handle<Symbol> key = isolate->factory()->promise_forwarding_handler_symbol(); |
| 1824 Handle<Object> forwarding_handler = JSReceiver::GetDataProperty(handler, key); |
| 1825 if (forwarding_handler->IsUndefined(isolate)) { |
| 1826 return true; |
| 1827 } |
| 1828 |
| 1829 // TODO(gsathya): Remove this once we get rid of deferred objects. |
| 1830 Handle<String> promise_str = isolate->factory()->promise_string(); |
| 1831 Handle<Object> deferred_promise_obj = |
| 1832 JSObject::GetDataProperty(deferred, promise_str); |
| 1833 if (!deferred_promise_obj->IsJSPromise()) { |
| 1834 return true; |
| 1835 } |
| 1836 |
| 1837 return InternalPromiseHasUserDefinedRejectHandler( |
| 1838 isolate, Handle<JSPromise>::cast(deferred_promise_obj)); |
| 1839 |
| 1840 // Otherwise, this is a real reject handler for the Promise |
| 1841 return true; |
| 1842 } |
| 1843 |
| 1844 bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate, |
| 1845 Handle<JSPromise> promise) { |
| 1846 // If this promise was marked as being handled by a catch block |
| 1847 // in an async function, then it has a user-defined reject handler. |
| 1848 if (promise->handled_hint()) return true; |
| 1849 |
| 1850 // If this Promise is subsumed by another Promise (a Promise resolved |
| 1851 // with another Promise, or an intermediate, hidden, throwaway Promise |
| 1852 // within async/await), then recurse on the outer Promise. |
| 1853 // In this case, the dependency is one possible way that the Promise |
| 1854 // could be resolved, so it does not subsume the other following cases. |
| 1855 Handle<Symbol> key = isolate->factory()->promise_handled_by_symbol(); |
| 1856 Handle<Object> outer_promise_obj = JSObject::GetDataProperty(promise, key); |
| 1857 if (outer_promise_obj->IsJSPromise() && |
| 1858 InternalPromiseHasUserDefinedRejectHandler( |
| 1859 isolate, Handle<JSPromise>::cast(outer_promise_obj))) { |
| 1860 return true; |
| 1861 } |
| 1862 |
| 1863 Handle<Object> queue(promise->reject_reactions(), isolate); |
| 1864 Handle<Object> deferred(promise->deferred(), isolate); |
| 1865 |
| 1866 if (queue->IsUndefined(isolate)) { |
| 1867 return false; |
| 1868 } |
| 1869 |
| 1870 if (queue->IsCallable()) { |
| 1871 return PromiseHandlerCheck(isolate, Handle<JSReceiver>::cast(queue), |
| 1872 Handle<JSObject>::cast(deferred)); |
| 1873 } |
| 1874 |
| 1875 Handle<FixedArray> queue_arr = Handle<FixedArray>::cast(queue); |
| 1876 Handle<FixedArray> deferred_arr = Handle<FixedArray>::cast(deferred); |
| 1877 for (int i = 0; i < deferred_arr->length(); i++) { |
| 1878 Handle<JSReceiver> queue_item(JSReceiver::cast(queue_arr->get(i))); |
| 1879 Handle<JSObject> deferred_item(JSObject::cast(deferred_arr->get(i))); |
| 1880 if (PromiseHandlerCheck(isolate, queue_item, deferred_item)) { |
| 1881 return true; |
| 1882 } |
| 1883 } |
| 1884 |
| 1885 return false; |
| 1886 } |
| 1887 |
| 1888 } // namespace |
| 1889 |
1811 bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) { | 1890 bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) { |
1812 Handle<JSFunction> fun = promise_has_user_defined_reject_handler(); | 1891 if (!promise->IsJSPromise()) return false; |
1813 Handle<Object> has_reject_handler; | 1892 return InternalPromiseHasUserDefinedRejectHandler( |
1814 // If we are, e.g., overflowing the stack, don't try to call out to JS | 1893 this, Handle<JSPromise>::cast(promise)); |
1815 if (!AllowJavascriptExecution::IsAllowed(this)) return false; | |
1816 // Call the registered function to check for a handler | |
1817 if (Execution::TryCall(this, fun, promise, 0, NULL) | |
1818 .ToHandle(&has_reject_handler)) { | |
1819 return has_reject_handler->IsTrue(this); | |
1820 } | |
1821 // If an exception is thrown in the course of execution of this built-in | |
1822 // function, it indicates either a bug, or a synthetic uncatchable | |
1823 // exception in the shutdown path. In either case, it's OK to predict either | |
1824 // way in DevTools. | |
1825 return false; | |
1826 } | 1894 } |
1827 | 1895 |
1828 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { | 1896 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
1829 Handle<Object> undefined = factory()->undefined_value(); | 1897 Handle<Object> undefined = factory()->undefined_value(); |
1830 ThreadLocalTop* tltop = thread_local_top(); | 1898 ThreadLocalTop* tltop = thread_local_top(); |
1831 if (tltop->promise_on_stack_ == NULL) return undefined; | 1899 if (tltop->promise_on_stack_ == NULL) return undefined; |
1832 // Find the top-most try-catch or try-finally handler. | 1900 // Find the top-most try-catch or try-finally handler. |
1833 CatchType prediction = PredictExceptionCatcher(); | 1901 CatchType prediction = PredictExceptionCatcher(); |
1834 if (prediction == NOT_CAUGHT || prediction == CAUGHT_BY_EXTERNAL) { | 1902 if (prediction == NOT_CAUGHT || prediction == CAUGHT_BY_EXTERNAL) { |
1835 return undefined; | 1903 return undefined; |
1836 } | 1904 } |
1837 Handle<Object> retval = undefined; | 1905 Handle<Object> retval = undefined; |
1838 PromiseOnStack* promise_on_stack = tltop->promise_on_stack_; | 1906 PromiseOnStack* promise_on_stack = tltop->promise_on_stack_; |
1839 for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) { | 1907 for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) { |
1840 switch (PredictException(it.frame())) { | 1908 switch (PredictException(it.frame())) { |
1841 case HandlerTable::UNCAUGHT: | 1909 case HandlerTable::UNCAUGHT: |
1842 continue; | 1910 continue; |
1843 case HandlerTable::CAUGHT: | 1911 case HandlerTable::CAUGHT: |
1844 case HandlerTable::DESUGARING: | 1912 case HandlerTable::DESUGARING: |
1845 if (retval->IsJSObject()) { | 1913 if (retval->IsJSPromise()) { |
1846 // Caught the result of an inner async/await invocation. | 1914 // Caught the result of an inner async/await invocation. |
1847 // Mark the inner promise as caught in the "synchronous case" so | 1915 // Mark the inner promise as caught in the "synchronous case" so |
1848 // that Debug::OnException will see. In the synchronous case, | 1916 // that Debug::OnException will see. In the synchronous case, |
1849 // namely in the code in an async function before the first | 1917 // namely in the code in an async function before the first |
1850 // await, the function which has this exception event has not yet | 1918 // await, the function which has this exception event has not yet |
1851 // returned, so the generated Promise has not yet been marked | 1919 // returned, so the generated Promise has not yet been marked |
1852 // by AsyncFunctionAwaitCaught with promiseHandledHintSymbol. | 1920 // by AsyncFunctionAwaitCaught with promiseHandledHintSymbol. |
1853 Handle<Symbol> key = factory()->promise_handled_hint_symbol(); | 1921 Handle<JSPromise>::cast(retval)->set_handled_hint(true); |
1854 JSObject::SetProperty(Handle<JSObject>::cast(retval), key, | |
1855 factory()->true_value(), STRICT) | |
1856 .Assert(); | |
1857 } | 1922 } |
1858 return retval; | 1923 return retval; |
1859 case HandlerTable::PROMISE: | 1924 case HandlerTable::PROMISE: |
1860 return promise_on_stack | 1925 return promise_on_stack |
1861 ? Handle<Object>::cast(promise_on_stack->promise()) | 1926 ? Handle<Object>::cast(promise_on_stack->promise()) |
1862 : undefined; | 1927 : undefined; |
1863 case HandlerTable::ASYNC_AWAIT: { | 1928 case HandlerTable::ASYNC_AWAIT: { |
1864 // If in the initial portion of async/await, continue the loop to pop up | 1929 // If in the initial portion of async/await, continue the loop to pop up |
1865 // successive async/await stack frames until an asynchronous one with | 1930 // successive async/await stack frames until an asynchronous one with |
1866 // dependents is found, or a non-async stack frame is encountered, in | 1931 // dependents is found, or a non-async stack frame is encountered, in |
(...skipping 1718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3585 // Then check whether this scope intercepts. | 3650 // Then check whether this scope intercepts. |
3586 if ((flag & intercept_mask_)) { | 3651 if ((flag & intercept_mask_)) { |
3587 intercepted_flags_ |= flag; | 3652 intercepted_flags_ |= flag; |
3588 return true; | 3653 return true; |
3589 } | 3654 } |
3590 return false; | 3655 return false; |
3591 } | 3656 } |
3592 | 3657 |
3593 } // namespace internal | 3658 } // namespace internal |
3594 } // namespace v8 | 3659 } // namespace v8 |
OLD | NEW |