OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
haraken
2017/04/07 04:47:46
2017
Mircea Trofin
2017/04/07 06:11:17
Done.
| |
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 "modules/wasm/WasmResponseExtensions.h" | |
6 | |
7 #include "bindings/core/v8/ExceptionState.h" | |
8 #include "bindings/core/v8/ScriptState.h" | |
9 #include "bindings/modules/v8/V8Response.h" | |
10 #include "modules/fetch/BodyStreamBuffer.h" | |
11 #include "wtf/RefPtr.h" | |
yhirano
2017/04/07 02:39:37
+ modules/fetch/FetchDataLoader.h
+ bindings/core/
Mircea Trofin
2017/04/07 06:11:16
done.
| |
12 | |
13 namespace blink { | |
14 | |
15 namespace { | |
16 | |
17 class FetchDataLoaderAsWasmModule final : public FetchDataLoader, | |
18 public BytesConsumer::Client { | |
19 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsWasmModule); | |
20 | |
21 public: | |
22 FetchDataLoaderAsWasmModule(v8::Isolate* isolate, | |
haraken
2017/04/07 04:47:46
Remove the isolate parameter. You can use scriptST
Mircea Trofin
2017/04/07 06:11:16
Done.
| |
23 ScriptPromiseResolver* resolver, | |
24 ScriptState* scriptState) | |
25 : m_resolver(resolver), m_builder(isolate), m_scriptState(scriptState) {} | |
26 | |
27 void start(BytesConsumer* consumer, | |
28 FetchDataLoader::Client* client) override { | |
29 DCHECK(!m_consumer); | |
30 DCHECK(!m_client); | |
31 m_client = client; | |
32 m_consumer = consumer; | |
33 m_consumer->setClient(this); | |
34 onStateChange(); | |
35 } | |
36 | |
37 void onStateChange() override { | |
38 while (true) { | |
39 // buffer is allocated by beginRead and de-allocated by endRead. | |
haraken
2017/04/07 04:47:46
beginRead just sets buffer to some address in an a
Mircea Trofin
2017/04/07 06:11:17
Yes, looking at https://cs.chromium.org/chromium/
| |
40 const char* buffer = nullptr; | |
41 size_t available = 0; | |
42 BytesConsumer::Result result = m_consumer->beginRead(&buffer, &available); | |
43 | |
44 if (result == BytesConsumer::Result::ShouldWait) | |
45 return; | |
46 if (result == BytesConsumer::Result::Ok) { | |
47 if (available > 0) { | |
48 DCHECK_NE(buffer, nullptr); | |
49 m_builder.OnBytesReceived(reinterpret_cast<const uint8_t*>(buffer), | |
50 available); | |
51 } | |
52 result = m_consumer->endRead(available); | |
53 } | |
54 switch (result) { | |
55 case BytesConsumer::Result::ShouldWait: | |
56 NOTREACHED(); | |
57 return; | |
58 case BytesConsumer::Result::Ok: { | |
59 break; | |
60 } | |
61 case BytesConsumer::Result::Done: { | |
62 v8::Isolate* isolate = m_resolver->getScriptState()->isolate(); | |
63 ScriptState::Scope scope(m_scriptState.get()); | |
64 v8::TryCatch trycatch(isolate); | |
65 v8::Local<v8::WasmCompiledModule> module; | |
66 if (m_builder.Finish().ToLocal(&module)) { | |
67 DCHECK(!trycatch.HasCaught()); | |
68 ScriptValue scriptValue(m_scriptState.get(), module); | |
69 m_resolver->resolve(scriptValue); | |
70 } else { | |
71 DCHECK(trycatch.HasCaught()); | |
72 m_resolver->reject(trycatch.Exception()); | |
73 trycatch.Reset(); | |
74 } | |
75 m_client->didFetchDataLoadedCustomFormat(); | |
76 return; | |
77 } | |
78 case BytesConsumer::Result::Error: { | |
79 // TODO(mtrofin): do we need an abort on the wasm side? | |
80 // Something like "m_outStream->abort()" maybe? | |
81 return ThrowTypeError(); | |
82 } | |
83 } | |
84 } | |
85 } | |
86 | |
87 void cancel() override { | |
88 m_consumer->cancel(); | |
89 return ThrowTypeError(); | |
90 } | |
91 | |
92 DEFINE_INLINE_TRACE() { | |
93 visitor->trace(m_consumer); | |
94 visitor->trace(m_resolver); | |
95 visitor->trace(m_client); | |
96 FetchDataLoader::trace(visitor); | |
97 BytesConsumer::Client::trace(visitor); | |
98 } | |
99 | |
100 private: | |
101 // TODO(mtrofin): replace with spec-ed error types, once spec clarifies | |
102 // what they are. | |
103 void ThrowTypeError() { | |
haraken
2017/04/07 04:47:46
throwTypeError
I'd prefer "rejectPromise" or some
Mircea Trofin
2017/04/07 06:11:17
Done.
| |
104 m_resolver->reject(V8ThrowException::createTypeError( | |
105 m_scriptState->isolate(), "Could not download wasm module")); | |
106 } | |
107 Member<BytesConsumer> m_consumer; | |
108 Member<ScriptPromiseResolver> m_resolver; | |
109 Member<FetchDataLoader::Client> m_client; | |
110 v8::WasmModuleObjectBuilder m_builder; | |
111 const RefPtr<ScriptState> m_scriptState; | |
112 }; | |
113 | |
114 // TODO(mtrofin): WasmDataLoaderClient is necessary so we may provide an | |
115 // argument to BodyStreamBuffer::startLoading, however, it fulfills | |
116 // a very small role. Consider refactoring to avoid it. | |
117 class WasmDataLoaderClient final | |
118 : public GarbageCollectedFinalized<WasmDataLoaderClient>, | |
119 public FetchDataLoader::Client { | |
120 WTF_MAKE_NONCOPYABLE(WasmDataLoaderClient); | |
121 USING_GARBAGE_COLLECTED_MIXIN(WasmDataLoaderClient); | |
122 | |
123 public: | |
124 explicit WasmDataLoaderClient(ScriptPromiseResolver* resolver) | |
125 : m_resolver(resolver) {} | |
126 | |
127 void didFetchDataLoadedCustomFormat() override {} | |
128 void didFetchDataLoadFailed() override { NOTREACHED(); } | |
129 DEFINE_INLINE_TRACE() { | |
130 visitor->trace(m_resolver); | |
131 FetchDataLoader::Client::trace(visitor); | |
132 } | |
133 | |
134 private: | |
135 Member<ScriptPromiseResolver> m_resolver; | |
yhirano
2017/04/07 02:39:37
You don't need this member.
Mircea Trofin
2017/04/07 06:11:16
Done.
| |
136 }; | |
137 | |
138 // This callback may be entered as a promise is resolved, or directly | |
139 // from the overload callback. | |
140 // See https://crbug.com/708238 for tracking avoiding the hand-generated code. | |
141 void compileFromResponseCallback( | |
142 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
143 ExceptionState exceptionState(args.GetIsolate(), | |
144 ExceptionState::ExecutionContext, "WebAssembly", | |
145 "compile"); | |
146 ExceptionToRejectPromiseScope rejectPromiseScope(args, exceptionState); | |
147 | |
148 ScriptState* scriptState = ScriptState::forReceiverObject(args); | |
149 if (!scriptState->getExecutionContext()) { | |
150 args.GetReturnValue().Set(ScriptPromise().v8Value()); | |
yhirano
2017/04/07 02:39:36
ScriptPromise().v8Value() is mere an empty v8 valu
haraken
2017/04/07 04:47:46
Nit: v8SetReturnValue()
| |
151 return; | |
152 } | |
153 | |
154 if (args.Length() < 1 || !args[0]->IsObject() || | |
155 !V8Response::hasInstance(args[0], args.GetIsolate())) { | |
156 args.GetReturnValue().Set( | |
haraken
2017/04/07 04:47:47
Nit: v8SetReturnValue()
Mircea Trofin
2017/04/07 06:11:16
I like that! Done.
| |
157 ScriptPromise::reject( | |
158 scriptState, V8ThrowException::createTypeError( | |
159 scriptState->isolate(), | |
160 "Promise argument must produce a Response object")) | |
yhirano
2017/04/07 02:39:36
Is "This function must be called with Promise<Resp
Mircea Trofin
2017/04/07 06:11:16
Done.
| |
161 .v8Value()); | |
162 return; | |
163 } | |
164 | |
165 Response* response = V8Response::toImpl(v8::Local<v8::Object>::Cast(args[0])); | |
166 ScriptPromise promise; | |
167 if (response->isBodyLocked() || response->bodyUsed()) { | |
168 promise = ScriptPromise::reject( | |
169 scriptState, | |
170 V8ThrowException::createTypeError( | |
171 scriptState->isolate(), | |
172 "Cannot compile WebAssembly.Module from an already read Response")); | |
173 } else { | |
174 ScriptPromiseResolver* resolver = | |
175 ScriptPromiseResolver::create(scriptState); | |
176 if (response->bodyBuffer()) { | |
177 promise = resolver->promise(); | |
178 response->bodyBuffer()->startLoading( | |
179 new FetchDataLoaderAsWasmModule(args.GetIsolate(), resolver, | |
180 scriptState), | |
181 new WasmDataLoaderClient(resolver)); | |
182 } else { | |
183 promise = ScriptPromise::reject( | |
184 scriptState, V8ThrowException::createTypeError( | |
185 scriptState->isolate(), | |
186 "Promise argument must produce a Response object")); | |
yhirano
2017/04/07 02:39:37
I think this message is confusing (from a differen
Mircea Trofin
2017/04/07 06:11:17
Done.
| |
187 } | |
188 } | |
189 args.GetReturnValue().Set(promise.v8Value()); | |
haraken
2017/04/07 04:47:46
Nit: v8SetReturnValue()
Mircea Trofin
2017/04/07 06:11:17
Done.
| |
190 } | |
191 | |
192 ScriptPromise wasmCompileFromPromise(v8::Isolate* isolate, | |
193 ScriptPromise promise) { | |
194 v8::Local<v8::Function> compileCallback = | |
195 v8::Function::New(isolate, compileFromResponseCallback); | |
196 return promise.then(compileCallback); | |
197 } | |
198 | |
199 // See https://crbug.com/708238 for tracking avoiding the hand-generated code. | |
haraken
2017/04/07 04:47:46
Add a comment about what spec this method is imple
Mircea Trofin
2017/04/07 06:11:17
Done.
| |
200 bool wasmCompileOverload(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
201 if (args.Length() < 1 || !args[0]->IsObject()) | |
202 return false; | |
203 | |
204 v8::Isolate* isolate = args.GetIsolate(); | |
205 ScriptState* scriptState = ScriptState::forReceiverObject(args); | |
206 | |
207 if (args[0]->IsPromise()) { | |
208 ScriptPromise scriptPromise = ScriptPromise(scriptState, args[0]); | |
209 args.GetReturnValue().Set( | |
haraken
2017/04/07 04:47:47
Nit: v8SetReturnValue()
Mircea Trofin
2017/04/07 06:11:16
Done.
| |
210 wasmCompileFromPromise(isolate, scriptPromise).v8Value()); | |
211 return true; | |
212 } | |
213 if (V8Response::hasInstance(args[0], args.GetIsolate())) { | |
214 ScriptPromiseResolver* scriptPromiseResolver = | |
215 ScriptPromiseResolver::create(scriptState); | |
216 ScriptValue wrappedResponse = ScriptValue::from(scriptState, args[0]); | |
haraken
2017/04/07 04:47:46
ScriptValue wrappedResponse(scriptState, args[0])
Mircea Trofin
2017/04/07 06:11:17
Ya, but I moved that line in the resolve() call be
| |
217 args.GetReturnValue().Set( | |
haraken
2017/04/07 04:47:46
Nit: v8SetReturnValue()
Mircea Trofin
2017/04/07 06:11:17
Done.
| |
218 (wasmCompileFromPromise(isolate, scriptPromiseResolver->promise())) | |
219 .v8Value()); | |
220 scriptPromiseResolver->resolve(wrappedResponse); | |
221 return true; | |
222 } | |
223 return false; | |
224 } | |
225 | |
226 } // namespace | |
227 | |
228 void WasmResponseExtensions::initialize(v8::Isolate* isolate) { | |
229 isolate->SetWasmCompileCallback(wasmCompileOverload); | |
230 } | |
231 | |
232 } // namespace blink | |
OLD | NEW |