OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 #include "bindings/v8/ScriptPromisePropertyBase.h" | |
7 | |
8 #include "bindings/v8/V8Binding.h" | |
9 #include "bindings/v8/V8HiddenValue.h" | |
10 #include "core/dom/ExecutionContext.h" | |
11 #include "wtf/text/StringBuilder.h" | |
12 | |
13 namespace WebCore { | |
14 | |
15 class ScriptPromisePropertyBase::PendingAction { | |
16 public: | |
17 PendingAction(v8::Isolate* isolate, v8::Handle<v8::Promise::Resolver> resolv er, v8::Handle<v8::Value> value, State state) | |
18 : m_resolver(isolate, resolver) | |
19 , m_value(isolate, value) | |
20 , m_state(state) { } | |
21 ~PendingAction() { } | |
22 | |
23 void execute(v8::Isolate*); | |
24 | |
25 protected: | |
26 ScopedPersistent<v8::Promise::Resolver> m_resolver; | |
27 ScopedPersistent<v8::Value> m_value; | |
28 State m_state; | |
29 }; | |
30 | |
31 void ScriptPromisePropertyBase::PendingAction::execute(v8::Isolate* isolate) | |
32 { | |
33 v8::HandleScope handleScope(isolate); | |
34 ScriptState::Scope scope(ScriptState::from(m_resolver.newLocal(isolate)->Cre ationContext())); | |
haraken
2014/07/01 06:29:13
It would be nicer to explicitly pass in the Script
| |
35 v8::Handle<v8::Promise::Resolver> resolver = m_resolver.newLocal(isolate); | |
36 m_resolver.clear(); | |
37 v8::Handle<v8::Value> value = m_value.newLocal(isolate); | |
38 m_value.clear(); | |
haraken
2014/07/01 06:29:13
Just to confirm: Even if we don't clear m_value an
dominicc (has gone to gerrit)
2014/07/02 04:02:16
Those are strong, so while the ScriptPromiseProper
| |
39 | |
40 switch (m_state) { | |
41 case Pending: | |
42 ASSERT_NOT_REACHED(); | |
43 break; | |
44 case Resolved: | |
45 resolver->Resolve(value); | |
46 break; | |
47 case Rejected: | |
48 resolver->Reject(value); | |
49 break; | |
50 } | |
51 } | |
52 | |
53 static v8::Handle<v8::String> makeName(v8::Isolate* isolate, const char* name, c onst char* suffix) | |
54 { | |
55 StringBuilder builder; | |
56 builder.append(name); | |
57 builder.append(suffix); | |
58 return v8String(isolate, builder.toString()); | |
59 } | |
60 | |
61 ScriptPromisePropertyBase::ScriptPromisePropertyBase(ExecutionContext* execution Context, const char* name) | |
62 : ActiveDOMObject(executionContext) | |
63 , m_isolate(toIsolate(executionContext)) | |
64 , m_state(Pending) | |
65 , m_inResume(false) | |
66 { | |
67 v8::HandleScope handleScope(m_isolate); | |
68 m_resolverName.set(m_isolate, makeName(m_isolate, name, "/Resolver")); | |
69 m_promiseName.set(m_isolate, makeName(m_isolate, name, "/Promise")); | |
70 } | |
71 | |
72 ScriptPromisePropertyBase::~ScriptPromisePropertyBase() | |
73 { | |
74 v8::HandleScope handleScope(m_isolate); | |
75 v8::Handle<v8::Object> wrapper = m_mainWorldWrapper.newLocal(m_isolate); | |
76 m_mainWorldWrapper.clear(); | |
haraken
2014/07/01 06:29:13
You don't need to call this, since it's destructed
| |
77 if (!wrapper.IsEmpty()) { | |
78 v8::Handle<v8::String> resolverName = m_resolverName.newLocal(m_isolate) ; | |
79 wrapper->DeleteHiddenValue(resolverName); | |
80 v8::Handle<v8::String> promiseName = m_promiseName.newLocal(m_isolate); | |
81 wrapper->DeleteHiddenValue(promiseName); | |
82 } | |
83 } | |
84 | |
85 static void clearHandle(const v8::WeakCallbackData<v8::Object, ScopedPersistent< v8::Object> >& data) | |
86 { | |
87 data.GetParameter()->clear(); | |
88 } | |
89 | |
90 ScriptPromise ScriptPromisePropertyBase::promise(DOMWrapperWorld& world) | |
91 { | |
92 ASSERT(executionContext() && !executionContext()->activeDOMObjectsAreStopped ()); | |
haraken
2014/07/01 06:29:12
How is this guaranteed?
dominicc (has gone to gerrit)
2014/07/02 04:02:16
It should be guaranteed by the caller.
Looking at
| |
93 | |
94 if (!world.isMainWorld()) { | |
95 // FIXME: Support isolated worlds. | |
96 return ScriptPromise(); | |
97 } | |
98 | |
99 v8::HandleScope handleScope(m_isolate); | |
100 ASSERT(m_isolate == toIsolate(executionContext())); | |
haraken
2014/07/01 06:29:13
You can remove this, since it must hold :)
| |
101 v8::Handle<v8::Context> context = toV8Context(executionContext(), world); | |
102 if (context.IsEmpty()) | |
103 return ScriptPromise(); | |
104 ScriptState* scriptState = ScriptState::from(context); | |
105 ScriptState::Scope scope(scriptState); | |
106 | |
107 v8::Handle<v8::String> resolverName = m_resolverName.newLocal(m_isolate); | |
108 v8::Handle<v8::String> promiseName = m_promiseName.newLocal(m_isolate); | |
109 | |
110 v8::Handle<v8::Object> wrapper = m_mainWorldWrapper.newLocal(m_isolate); | |
111 if (wrapper.IsEmpty()) { | |
112 wrapper = holder(context->Global(), m_isolate); | |
113 ASSERT(!wrapper.IsEmpty()); | |
114 ASSERT(V8HiddenValue::getHiddenValue(m_isolate, wrapper, resolverName).I sEmpty()); | |
115 ASSERT(V8HiddenValue::getHiddenValue(m_isolate, wrapper, promiseName).Is Empty()); | |
116 m_mainWorldWrapper.set(m_isolate, wrapper); | |
117 m_mainWorldWrapper.setWeak(&m_mainWorldWrapper, &clearHandle); | |
118 } | |
119 ASSERT(wrapper->CreationContext() == context); | |
120 | |
121 v8::Handle<v8::Promise> promise = V8HiddenValue::getHiddenValue(m_isolate, w rapper, promiseName).As<v8::Promise>(); | |
122 if (!promise.IsEmpty()) { | |
123 // Return cached Promise | |
124 return ScriptPromise(scriptState, promise); | |
125 } | |
126 | |
127 // Create and cache the Promise | |
128 v8::Handle<v8::Promise::Resolver> resolver = v8::Promise::Resolver::New(m_is olate); | |
129 promise = resolver->GetPromise(); | |
130 V8HiddenValue::setHiddenValue(m_isolate, wrapper, promiseName, promise); | |
131 V8HiddenValue::setHiddenValue(m_isolate, promise, promiseName, wrapper); | |
haraken
2014/07/01 06:29:12
Add comments (probably in a header file) about how
| |
132 | |
133 switch (m_state) { | |
134 case Pending: | |
135 // Cache the resolver too | |
136 V8HiddenValue::setHiddenValue(m_isolate, wrapper, resolverName, resolver ); | |
137 break; | |
138 case Resolved: | |
139 case Rejected: | |
140 resolveOrReject(resolver); | |
141 break; | |
142 } | |
143 | |
144 return ScriptPromise(scriptState, promise); | |
145 } | |
146 | |
147 void ScriptPromisePropertyBase::settle(State targetState) | |
148 { | |
149 ASSERT(executionContext() && !executionContext()->activeDOMObjectsAreStopped ()); | |
150 ASSERT(m_state == Pending); | |
151 ASSERT(targetState == Resolved || targetState == Rejected); | |
152 | |
153 m_state = targetState; | |
154 | |
155 v8::HandleScope handleScope(m_isolate); | |
156 v8::Handle<v8::Object> wrapper = m_mainWorldWrapper.newLocal(m_isolate); | |
157 if (wrapper.IsEmpty()) | |
158 return; // wrapper has died or was never populated | |
159 ScriptState::Scope scope(ScriptState::from(wrapper->CreationContext())); | |
160 | |
161 v8::Handle<v8::String> resolverName = m_resolverName.newLocal(m_isolate); | |
162 v8::Handle<v8::Promise::Resolver> resolver = V8HiddenValue::getHiddenValue(m _isolate, wrapper, resolverName).As<v8::Promise::Resolver>(); | |
163 | |
164 V8HiddenValue::deleteHiddenValue(m_isolate, wrapper, resolverName); | |
165 resolveOrReject(resolver); | |
166 } | |
167 | |
168 void ScriptPromisePropertyBase::resolveOrReject(v8::Handle<v8::Promise::Resolver > resolver) | |
169 { | |
170 ASSERT(m_state == Resolved || m_state == Rejected); | |
171 | |
172 v8::Handle<v8::Value> value; | |
173 switch (m_state) { | |
174 case Pending: | |
175 ASSERT_NOT_REACHED(); | |
176 break; | |
177 case Resolved: | |
178 value = resolvedValue(resolver->CreationContext()->Global(), m_isolate); | |
179 break; | |
180 case Rejected: | |
181 value = rejectedValue(resolver->CreationContext()->Global(), m_isolate); | |
182 break; | |
183 } | |
184 | |
185 if (executionContext()->activeDOMObjectsAreSuspended()) { | |
186 enqueuePendingAction(resolver, value, m_state); | |
187 return; | |
188 } | |
189 | |
190 switch (m_state) { | |
191 case Pending: | |
192 ASSERT_NOT_REACHED(); | |
193 break; | |
194 case Resolved: | |
195 resolver->Resolve(value); | |
196 break; | |
197 case Rejected: | |
198 resolver->Reject(value); | |
199 break; | |
200 } | |
201 } | |
202 | |
203 void ScriptPromisePropertyBase::enqueuePendingAction(v8::Handle<v8::Promise::Res olver> resolver, v8::Handle<v8::Value> value, State state) | |
204 { | |
205 if (m_pending.isEmpty()) | |
206 setPendingActivity(this); | |
haraken
2014/07/01 06:29:13
setPendingActivity() is deprecated, and we don't w
| |
207 m_pending.append(adoptPtr(new PendingAction(m_isolate, resolver, value, stat e))); | |
208 } | |
209 | |
210 void ScriptPromisePropertyBase::resume() | |
211 { | |
212 ASSERT_WITH_SECURITY_IMPLICATION(!m_inResume); | |
haraken
2014/07/01 06:29:13
Is there any reason you want to use _WITH_SECURITY
| |
213 if (!hasPendingActivity()) | |
214 return; | |
215 ASSERT(m_pending.size()); | |
216 m_inResume = true; | |
217 size_t i = 0; | |
218 while (i < m_pending.size() && executionContext() && !executionContext()->ac tiveDOMObjectsAreSuspended() && !executionContext()->activeDOMObjectsAreStopped( )) | |
haraken
2014/07/01 06:29:13
Add a comment and mention that the following execu
| |
219 m_pending[i++]->execute(m_isolate); | |
220 if (m_pending.size()) | |
221 m_pending.remove(0, i); | |
haraken
2014/07/01 06:29:13
Probably you can use a linked list for m_pending a
| |
222 if (m_pending.isEmpty()) | |
223 unsetPendingActivity(this); | |
224 } | |
225 | |
226 void ScriptPromisePropertyBase::stop() | |
227 { | |
228 if (m_pending.size()) | |
229 unsetPendingActivity(this); | |
230 m_pending.clear(); | |
231 } | |
232 | |
233 } // namespace WebCore | |
OLD | NEW |