bea7ee005b35e8a2539a646d48f5a3dd828425c0
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMPromise.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSDOMPromise.h"
28
29 #include "ExceptionCode.h"
30 #include "JSDOMError.h"
31 #include <builtins/BuiltinNames.h>
32 #include <runtime/Exception.h>
33 #include <runtime/JSONObject.h>
34 #include <runtime/JSPromiseConstructor.h>
35
36 using namespace JSC;
37
38 namespace WebCore {
39
40 DeferredWrapper::DeferredWrapper(ExecState*, JSDOMGlobalObject* globalObject, JSPromiseDeferred* promiseDeferred)
41     : ActiveDOMCallback(globalObject->scriptExecutionContext())
42     , m_deferred(promiseDeferred)
43     , m_globalObject(globalObject)
44 {
45     globalObject->vm().heap.writeBarrier(globalObject, promiseDeferred);
46     m_globalObject->deferredWrappers().add(this);
47 }
48
49 DeferredWrapper::~DeferredWrapper()
50 {
51     clear();
52 }
53
54 void DeferredWrapper::clear()
55 {
56     ASSERT(!m_deferred || m_globalObject);
57     if (m_deferred && m_globalObject)
58         m_globalObject->deferredWrappers().remove(this);
59     m_deferred.clear();
60 }
61
62 void DeferredWrapper::contextDestroyed()
63 {
64     ActiveDOMCallback::contextDestroyed();
65     clear();
66 }
67
68 JSC::JSValue DeferredWrapper::promise() const
69 {
70     ASSERT(m_deferred);
71     return m_deferred->promise();
72 }
73
74 void DeferredWrapper::callFunction(ExecState& exec, JSValue function, JSValue resolution)
75 {
76     if (!canInvokeCallback())
77         return;
78
79     CallData callData;
80     CallType callType = getCallData(function, callData);
81     ASSERT(callType != CallType::None);
82
83     MarkedArgumentBuffer arguments;
84     arguments.append(resolution);
85
86     call(&exec, function, callType, callData, jsUndefined(), arguments);
87
88     clear();
89 }
90
91 void DeferredWrapper::reject(ExceptionCode ec, const String& message)
92 {
93     if (isSuspended())
94         return;
95
96     ASSERT(m_deferred);
97     ASSERT(m_globalObject);
98     JSC::ExecState* state = m_globalObject->globalExec();
99     JSC::JSLockHolder locker(state);
100     reject(*state, createDOMException(state, ec, message));
101 }
102
103 void rejectPromiseWithExceptionIfAny(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSPromiseDeferred& promiseDeferred)
104 {
105     VM& vm = state.vm();
106     auto scope = DECLARE_CATCH_SCOPE(vm);
107
108     if (!scope.exception())
109         return;
110
111     JSValue error = scope.exception()->value();
112     scope.clearException();
113
114     DeferredWrapper::create(&state, &globalObject, &promiseDeferred)->reject(error);
115 }
116
117 JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::ExecState& state, const String& errorMessage)
118 {
119     ASSERT(state.lexicalGlobalObject());
120     auto& globalObject = *state.lexicalGlobalObject();
121
122     auto promiseConstructor = globalObject.promiseConstructor();
123     auto rejectFunction = promiseConstructor->get(&state, state.vm().propertyNames->builtinNames().rejectPrivateName());
124     auto rejectionValue = createTypeError(&state, errorMessage);
125
126     CallData callData;
127     auto callType = getCallData(rejectFunction, callData);
128     ASSERT(callType != CallType::None);
129
130     MarkedArgumentBuffer arguments;
131     arguments.append(rejectionValue);
132
133     return JSValue::encode(call(&state, rejectFunction, callType, callData, promiseConstructor, arguments));
134 }
135
136 static inline JSC::JSValue parseAsJSON(JSC::ExecState* state, const String& data)
137 {
138     JSC::JSLockHolder lock(state);
139     return JSC::JSONParse(state, data);
140 }
141
142 void fulfillPromiseWithJSON(Ref<DeferredWrapper>&& promise, const String& data)
143 {
144     JSC::JSValue value = parseAsJSON(promise->globalObject()->globalExec(), data);
145     if (!value)
146         promise->reject(SYNTAX_ERR);
147     else
148         promise->resolve(value);
149 }
150
151 void fulfillPromiseWithArrayBuffer(Ref<DeferredWrapper>&& promise, ArrayBuffer* arrayBuffer)
152 {
153     if (!arrayBuffer) {
154         promise->reject<JSValue>(createOutOfMemoryError(promise->globalObject()->globalExec()));
155         return;
156     }
157     promise->resolve(arrayBuffer);
158 }
159
160 void fulfillPromiseWithArrayBuffer(Ref<DeferredWrapper>&& promise, const void* data, size_t length)
161 {
162     fulfillPromiseWithArrayBuffer(WTFMove(promise), ArrayBuffer::tryCreate(data, length).get());
163 }
164
165 }