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; | |
1825 if (JSReceiver::GetProperty(handler, key).ToHandle(&forwarding_handler)) { | |
Yang
2016/12/23 08:40:08
Since we do not expect any getters or other side e
gsathya
2016/12/23 17:59:44
Done.
| |
1826 if (forwarding_handler->IsUndefined(isolate)) { | |
1827 return true; | |
1828 } | |
1829 | |
1830 // TODO(gsathya): Remove this once we get rid of deferred objects. | |
1831 Handle<String> promise_str = isolate->factory()->promise_string(); | |
1832 Handle<Object> deferred_promise_obj; | |
1833 if (JSObject::GetProperty(deferred, promise_str) | |
1834 .ToHandle(&deferred_promise_obj)) { | |
1835 if (!deferred_promise_obj->IsJSPromise()) { | |
1836 return true; | |
1837 } | |
1838 | |
1839 return InternalPromiseHasUserDefinedRejectHandler( | |
1840 isolate, Handle<JSPromise>::cast(deferred_promise_obj)); | |
1841 } | |
1842 } | |
1843 | |
1844 // Otherwise, this is a real reject handler for the Promise | |
1845 return true; | |
1846 } | |
1847 | |
1848 bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate, | |
1849 Handle<JSPromise> promise) { | |
1850 // If this promise was marked as being handled by a catch block | |
1851 // in an async function, then it has a user-defined reject handler. | |
1852 if (promise->handled_hint()) return true; | |
1853 | |
1854 // If this Promise is subsumed by another Promise (a Promise resolved | |
1855 // with another Promise, or an intermediate, hidden, throwaway Promise | |
1856 // within async/await), then recurse on the outer Promise. | |
1857 // In this case, the dependency is one possible way that the Promise | |
1858 // could be resolved, so it does not subsume the other following cases. | |
1859 Handle<Symbol> key = isolate->factory()->promise_handled_by_symbol(); | |
1860 Handle<Object> outer_promise_obj; | |
1861 if (JSObject::GetProperty(promise, key).ToHandle(&outer_promise_obj)) { | |
1862 if (outer_promise_obj->IsJSPromise() && | |
1863 InternalPromiseHasUserDefinedRejectHandler( | |
1864 isolate, Handle<JSPromise>::cast(outer_promise_obj))) { | |
1865 return true; | |
1866 } | |
1867 } | |
1868 | |
1869 Handle<Object> queue(promise->reject_reactions(), isolate); | |
1870 Handle<Object> deferred(promise->deferred(), isolate); | |
1871 | |
1872 if (queue->IsUndefined(isolate)) { | |
1873 return false; | |
1874 } | |
1875 | |
1876 if (queue->IsCallable()) { | |
1877 return PromiseHandlerCheck(isolate, Handle<JSReceiver>::cast(queue), | |
1878 Handle<JSObject>::cast(deferred)); | |
1879 } | |
1880 | |
1881 Handle<FixedArray> queue_arr = Handle<FixedArray>::cast(queue); | |
1882 Handle<FixedArray> deferred_arr = Handle<FixedArray>::cast(deferred); | |
1883 for (int i = 0; i < deferred_arr->length(); i++) { | |
1884 Handle<JSReceiver> queue_item(JSReceiver::cast(queue_arr->get(i))); | |
1885 Handle<JSObject> deferred_item(JSObject::cast(deferred_arr->get(i))); | |
1886 if (PromiseHandlerCheck(isolate, queue_item, deferred_item)) { | |
1887 return true; | |
1888 } | |
1889 } | |
1890 | |
1891 return false; | |
1892 } | |
1893 | |
1894 } // namespace | |
1895 | |
1811 bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) { | 1896 bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) { |
1812 Handle<JSFunction> fun = promise_has_user_defined_reject_handler(); | 1897 if (!promise->IsJSPromise()) return false; |
1813 Handle<Object> has_reject_handler; | 1898 return InternalPromiseHasUserDefinedRejectHandler( |
1814 // If we are, e.g., overflowing the stack, don't try to call out to JS | 1899 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 } | 1900 } |
1827 | 1901 |
1828 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { | 1902 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
1829 Handle<Object> undefined = factory()->undefined_value(); | 1903 Handle<Object> undefined = factory()->undefined_value(); |
1830 ThreadLocalTop* tltop = thread_local_top(); | 1904 ThreadLocalTop* tltop = thread_local_top(); |
1831 if (tltop->promise_on_stack_ == NULL) return undefined; | 1905 if (tltop->promise_on_stack_ == NULL) return undefined; |
1832 // Find the top-most try-catch or try-finally handler. | 1906 // Find the top-most try-catch or try-finally handler. |
1833 CatchType prediction = PredictExceptionCatcher(); | 1907 CatchType prediction = PredictExceptionCatcher(); |
1834 if (prediction == NOT_CAUGHT || prediction == CAUGHT_BY_EXTERNAL) { | 1908 if (prediction == NOT_CAUGHT || prediction == CAUGHT_BY_EXTERNAL) { |
1835 return undefined; | 1909 return undefined; |
1836 } | 1910 } |
1837 Handle<Object> retval = undefined; | 1911 Handle<Object> retval = undefined; |
1838 PromiseOnStack* promise_on_stack = tltop->promise_on_stack_; | 1912 PromiseOnStack* promise_on_stack = tltop->promise_on_stack_; |
1839 for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) { | 1913 for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) { |
1840 switch (PredictException(it.frame())) { | 1914 switch (PredictException(it.frame())) { |
1841 case HandlerTable::UNCAUGHT: | 1915 case HandlerTable::UNCAUGHT: |
1842 continue; | 1916 continue; |
1843 case HandlerTable::CAUGHT: | 1917 case HandlerTable::CAUGHT: |
1844 case HandlerTable::DESUGARING: | 1918 case HandlerTable::DESUGARING: |
1845 if (retval->IsJSObject()) { | 1919 if (retval->IsJSPromise()) { |
1846 // Caught the result of an inner async/await invocation. | 1920 // Caught the result of an inner async/await invocation. |
1847 // Mark the inner promise as caught in the "synchronous case" so | 1921 // Mark the inner promise as caught in the "synchronous case" so |
1848 // that Debug::OnException will see. In the synchronous case, | 1922 // that Debug::OnException will see. In the synchronous case, |
1849 // namely in the code in an async function before the first | 1923 // namely in the code in an async function before the first |
1850 // await, the function which has this exception event has not yet | 1924 // await, the function which has this exception event has not yet |
1851 // returned, so the generated Promise has not yet been marked | 1925 // returned, so the generated Promise has not yet been marked |
1852 // by AsyncFunctionAwaitCaught with promiseHandledHintSymbol. | 1926 // by AsyncFunctionAwaitCaught with promiseHandledHintSymbol. |
1853 Handle<Symbol> key = factory()->promise_handled_hint_symbol(); | 1927 Handle<JSPromise>::cast(retval)->set_handled_hint(true); |
1854 JSObject::SetProperty(Handle<JSObject>::cast(retval), key, | |
1855 factory()->true_value(), STRICT) | |
1856 .Assert(); | |
1857 } | 1928 } |
1858 return retval; | 1929 return retval; |
1859 case HandlerTable::PROMISE: | 1930 case HandlerTable::PROMISE: |
1860 return promise_on_stack | 1931 return promise_on_stack |
1861 ? Handle<Object>::cast(promise_on_stack->promise()) | 1932 ? Handle<Object>::cast(promise_on_stack->promise()) |
1862 : undefined; | 1933 : undefined; |
1863 case HandlerTable::ASYNC_AWAIT: { | 1934 case HandlerTable::ASYNC_AWAIT: { |
1864 // If in the initial portion of async/await, continue the loop to pop up | 1935 // 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 | 1936 // successive async/await stack frames until an asynchronous one with |
1866 // dependents is found, or a non-async stack frame is encountered, in | 1937 // 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. | 3656 // Then check whether this scope intercepts. |
3586 if ((flag & intercept_mask_)) { | 3657 if ((flag & intercept_mask_)) { |
3587 intercepted_flags_ |= flag; | 3658 intercepted_flags_ |= flag; |
3588 return true; | 3659 return true; |
3589 } | 3660 } |
3590 return false; | 3661 return false; |
3591 } | 3662 } |
3592 | 3663 |
3593 } // namespace internal | 3664 } // namespace internal |
3594 } // namespace v8 | 3665 } // namespace v8 |
OLD | NEW |