Chromium Code Reviews| 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 |