Chromium Code Reviews| 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 |