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

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

Issue 2780693003: [wasm] response-based compile APIs (Closed)
Patch Set: . 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 2017 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 "modules/wasm/WasmResponseExtensions.h"
6
7 #include "bindings/core/v8/ExceptionState.h"
8 #include "bindings/core/v8/ScriptPromise.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h"
10 #include "bindings/core/v8/ScriptState.h"
11 #include "bindings/modules/v8/V8Response.h"
12 #include "modules/fetch/BodyStreamBuffer.h"
13 #include "modules/fetch/FetchDataLoader.h"
14 #include "platform/heap/Handle.h"
15 #include "wtf/RefPtr.h"
16
17 namespace blink {
18
19 namespace {
20
21 class FetchDataLoaderAsWasmModule final : public FetchDataLoader,
22 public BytesConsumer::Client {
23 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsWasmModule);
24
25 public:
26 FetchDataLoaderAsWasmModule(ScriptPromiseResolver* resolver,
27 ScriptState* scriptState)
28 : m_resolver(resolver),
29 m_builder(scriptState->isolate()),
30 m_scriptState(scriptState) {}
31
32 void start(BytesConsumer* consumer,
33 FetchDataLoader::Client* client) override {
34 DCHECK(!m_consumer);
35 DCHECK(!m_client);
36 m_client = client;
37 m_consumer = consumer;
38 m_consumer->setClient(this);
39 onStateChange();
40 }
41
42 void onStateChange() override {
43 while (true) {
44 // buffer is allocated by beginRead and de-allocated by endRead.
haraken 2017/04/07 10:22:40 allocated / deallocated sounds misleading to me. b
Mircea Trofin 2017/04/07 15:33:08 True - rephrased.
45 const char* buffer = nullptr;
46 size_t available = 0;
47 BytesConsumer::Result result = m_consumer->beginRead(&buffer, &available);
48
49 if (result == BytesConsumer::Result::ShouldWait)
50 return;
51 if (result == BytesConsumer::Result::Ok) {
52 if (available > 0) {
53 DCHECK_NE(buffer, nullptr);
54 m_builder.OnBytesReceived(reinterpret_cast<const uint8_t*>(buffer),
55 available);
56 }
57 result = m_consumer->endRead(available);
58 }
59 switch (result) {
60 case BytesConsumer::Result::ShouldWait:
61 NOTREACHED();
62 return;
63 case BytesConsumer::Result::Ok: {
64 break;
65 }
66 case BytesConsumer::Result::Done: {
67 v8::Isolate* isolate = m_scriptState->isolate();
68 ScriptState::Scope scope(m_scriptState.get());
69 v8::TryCatch trycatch(isolate);
70 v8::Local<v8::WasmCompiledModule> module;
71 if (m_builder.Finish().ToLocal(&module)) {
72 DCHECK(!trycatch.HasCaught());
73 ScriptValue scriptValue(m_scriptState.get(), module);
74 m_resolver->resolve(scriptValue);
75 } else {
76 DCHECK(trycatch.HasCaught());
77 m_resolver->reject(trycatch.Exception());
78 trycatch.Reset();
haraken 2017/04/07 10:22:40 I don't fully understand why you need to reset it.
Mircea Trofin 2017/04/07 15:33:09 Granted, the destructor of TryCatch clears the exc
79 }
80 m_client->didFetchDataLoadedCustomFormat();
81 return;
82 }
83 case BytesConsumer::Result::Error: {
84 // TODO(mtrofin): do we need an abort on the wasm side?
85 // Something like "m_outStream->abort()" maybe?
86 return rejectPromise();
87 }
88 }
89 }
90 }
91
92 void cancel() override {
93 m_consumer->cancel();
94 return rejectPromise();
95 }
96
97 DEFINE_INLINE_TRACE() {
98 visitor->trace(m_consumer);
99 visitor->trace(m_resolver);
100 visitor->trace(m_client);
101 FetchDataLoader::trace(visitor);
102 BytesConsumer::Client::trace(visitor);
103 }
104
105 private:
106 // TODO(mtrofin): replace with spec-ed error types, once spec clarifies
107 // what they are.
108 void rejectPromise() {
109 m_resolver->reject(V8ThrowException::createTypeError(
110 m_scriptState->isolate(), "Could not download wasm module"));
111 }
112 Member<BytesConsumer> m_consumer;
113 Member<ScriptPromiseResolver> m_resolver;
114 Member<FetchDataLoader::Client> m_client;
115 v8::WasmModuleObjectBuilder m_builder;
116 const RefPtr<ScriptState> m_scriptState;
117 };
118
119 // TODO(mtrofin): WasmDataLoaderClient is necessary so we may provide an
120 // argument to BodyStreamBuffer::startLoading, however, it fulfills
121 // a very small role. Consider refactoring to avoid it.
122 class WasmDataLoaderClient final
123 : public GarbageCollectedFinalized<WasmDataLoaderClient>,
124 public FetchDataLoader::Client {
125 WTF_MAKE_NONCOPYABLE(WasmDataLoaderClient);
126 USING_GARBAGE_COLLECTED_MIXIN(WasmDataLoaderClient);
127
128 public:
129 explicit WasmDataLoaderClient() {}
130 void didFetchDataLoadedCustomFormat() override {}
131 void didFetchDataLoadFailed() override { NOTREACHED(); }
132 };
133
134 // This callback may be entered as a promise is resolved, or directly
135 // from the overload callback.
136 // See
137 // https://github.com/WebAssembly/design/blob/master/Web.md#webassemblycompile
138 void compileFromResponseCallback(
139 const v8::FunctionCallbackInfo<v8::Value>& args) {
140 ExceptionState exceptionState(args.GetIsolate(),
141 ExceptionState::ExecutionContext, "WebAssembly",
142 "compile");
143 ExceptionToRejectPromiseScope rejectPromiseScope(args, exceptionState);
144
145 ScriptState* scriptState = ScriptState::forReceiverObject(args);
146 if (!scriptState->getExecutionContext()) {
147 v8SetReturnValue(args, ScriptPromise().v8Value());
148 return;
149 }
150
151 if (args.Length() < 1 || !args[0]->IsObject() ||
152 !V8Response::hasInstance(args[0], args.GetIsolate())) {
153 v8SetReturnValue(
154 args, ScriptPromise::reject(
155 scriptState, V8ThrowException::createTypeError(
156 scriptState->isolate(),
157 "Promise argument must be called with a "
158 "Promise<Response> object"))
159 .v8Value());
160 return;
161 }
162
163 Response* response = V8Response::toImpl(v8::Local<v8::Object>::Cast(args[0]));
164 ScriptPromise promise;
165 if (response->isBodyLocked() || response->bodyUsed()) {
166 promise = ScriptPromise::reject(
167 scriptState,
168 V8ThrowException::createTypeError(
169 scriptState->isolate(),
170 "Cannot compile WebAssembly.Module from an already read Response"));
171 } else {
172 ScriptPromiseResolver* resolver =
173 ScriptPromiseResolver::create(scriptState);
174 if (response->bodyBuffer()) {
175 promise = resolver->promise();
176 response->bodyBuffer()->startLoading(
177 new FetchDataLoaderAsWasmModule(resolver, scriptState),
178 new WasmDataLoaderClient());
179 } else {
180 promise = ScriptPromise::reject(
181 scriptState,
182 V8ThrowException::createTypeError(
183 scriptState->isolate(), "Response object has a null body."));
184 }
185 }
186 v8SetReturnValue(args, promise.v8Value());
187 }
188
189 // See https://crbug.com/708238 for tracking avoiding the hand-generated code.
190 bool wasmCompileOverload(const v8::FunctionCallbackInfo<v8::Value>& args) {
191 if (args.Length() < 1 || !args[0]->IsObject())
192 return false;
193
194 if (!args[0]->IsPromise() &&
195 !V8Response::hasInstance(args[0], args.GetIsolate()))
196 return false;
197
198 v8::Isolate* isolate = args.GetIsolate();
199 ScriptState* scriptState = ScriptState::forReceiverObject(args);
200
201 v8::Local<v8::Function> compileCallback =
202 v8::Function::New(isolate, compileFromResponseCallback);
203
yhirano 2017/04/07 07:39:47 V8SetReturnValue(args, ScriptPromise::cast(scriptS
Mircea Trofin 2017/04/07 15:33:08 Nice! Thanks!
204 ScriptPromiseResolver* scriptPromiseResolver =
205 ScriptPromiseResolver::create(scriptState);
206 // treat either case of parameter as
207 // Promise.resolve(parameter)
208 // as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
209
210 // Ending with:
211 // return Promise.resolve(parameter).then(compileCallback);
212 ScriptPromise parameterAsPromise = scriptPromiseResolver->promise();
213 v8SetReturnValue(args, parameterAsPromise.then(compileCallback).v8Value());
214
215 // resolve the first parameter promise.
216 scriptPromiseResolver->resolve(ScriptValue::from(scriptState, args[0]));
217 return true;
218 }
219
220 } // namespace
221
222 void WasmResponseExtensions::initialize(v8::Isolate* isolate) {
223 isolate->SetWasmCompileCallback(wasmCompileOverload);
224 }
225
226 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698