Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(711)

Side by Side Diff: third_party/WebKit/Source/modules/wasm/WasmResponseExtensions.cpp

Issue 2780693003: [wasm] response-based compile APIs (Closed)
Patch Set: no specific OWNERS for now Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698