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

Side by Side Diff: src/wasm/wasm-js.cc

Issue 2695813005: [wasm] Split the compilation and instantiation API into sync and async methods. (Closed)
Patch Set: [wasm] Split the compilation and instantiation API into sync and async methods. Created 3 years, 10 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
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/api-natives.h" 5 #include "src/api-natives.h"
6 #include "src/api.h" 6 #include "src/api.h"
7 #include "src/asmjs/asm-js.h" 7 #include "src/asmjs/asm-js.h"
8 #include "src/asmjs/asm-typer.h" 8 #include "src/asmjs/asm-typer.h"
9 #include "src/asmjs/asm-wasm-builder.h" 9 #include "src/asmjs/asm-wasm-builder.h"
10 #include "src/assert-scope.h" 10 #include "src/assert-scope.h"
(...skipping 13 matching lines...) Expand all
24 #include "src/wasm/wasm-objects.h" 24 #include "src/wasm/wasm-objects.h"
25 #include "src/wasm/wasm-result.h" 25 #include "src/wasm/wasm-result.h"
26 26
27 typedef uint8_t byte; 27 typedef uint8_t byte;
28 28
29 using v8::internal::wasm::ErrorThrower; 29 using v8::internal::wasm::ErrorThrower;
30 30
31 namespace v8 { 31 namespace v8 {
32 32
33 namespace { 33 namespace {
34 // TODO(wasm): move brand check to the respective types, and don't throw
35 // in it, rather, use a provided ErrorThrower, or let caller handle it.
36 static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) {
37 if (!value->IsJSObject()) return false;
38 i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
39 Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
40 return !has_brand.IsNothing() && has_brand.ToChecked();
Clemens Hammacher 2017/02/16 20:36:57 return has_brand.FromMaybe(false);
titzer 2017/02/17 13:17:53 Done.
41 }
42
43 static bool BrandCheck(ErrorThrower* thrower, i::Handle<i::Object> value,
ahaas 2017/02/17 12:19:04 nit: having thrower as the third parameter would m
titzer 2017/02/17 13:17:53 Done. I thought we were more consistent about put
44 i::Handle<i::Symbol> sym, const char* msg) {
45 return HasBrand(value, sym) ? true : (thrower->TypeError("%s", msg), false);
46 }
47
34 i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) { 48 i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
35 return isolate->factory()->NewStringFromAsciiChecked(str); 49 return isolate->factory()->NewStringFromAsciiChecked(str);
36 } 50 }
37 Local<String> v8_str(Isolate* isolate, const char* str) { 51 Local<String> v8_str(Isolate* isolate, const char* str) {
38 return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str)); 52 return Utils::ToLocal(v8_str(reinterpret_cast<i::Isolate*>(isolate), str));
39 } 53 }
40 54
41 struct RawBuffer { 55 i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
42 const byte* start; 56 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
43 const byte* end; 57 v8::Isolate* isolate = args.GetIsolate();
44 size_t size() { return static_cast<size_t>(end - start); } 58 i::MaybeHandle<i::WasmModuleObject> nothing;
45 }; 59 if (args.Length() < 1) {
60 thrower->TypeError("Argument 0 must be a WebAssembly.Module");
61 return nothing;
Clemens Hammacher 2017/02/16 20:36:57 You really don't like "return {};"? What does {} r
titzer 2017/02/17 13:17:53 Done. Here and elsewhere in this file.
62 }
46 63
47 RawBuffer GetRawBufferSource( 64 Local<Context> context = isolate->GetCurrentContext();
48 v8::Local<v8::Value> source, ErrorThrower* thrower) { 65 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
66 if (!BrandCheck(thrower, Utils::OpenHandle(*args[0]),
67 i::Handle<i::Symbol>(i_context->wasm_module_sym()),
Clemens Hammacher 2017/02/16 20:36:57 this can we shortened to i::handle(i->context...)
titzer 2017/02/17 13:17:53 Done.
68 "Argument 0 must be a WebAssembly.Module")) {
69 return nothing;
70 }
71
72 Local<Object> module_obj = Local<Object>::Cast(args[0]);
73 return i::Handle<i::WasmModuleObject>::cast(
74 v8::Utils::OpenHandle(*module_obj));
75 }
76
77 i::wasm::ModuleWireBytes GetFirstArgumentAsBytes(
78 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
79 if (args.Length() < 1) {
80 thrower->TypeError("Argument 0 must be a buffer source");
81 return i::wasm::ModuleWireBytes(nullptr, nullptr);
82 }
83
49 const byte* start = nullptr; 84 const byte* start = nullptr;
50 const byte* end = nullptr; 85 const byte* end = nullptr;
51 86 v8::Local<v8::Value> source = args[0];
52 if (source->IsArrayBuffer()) { 87 if (source->IsArrayBuffer()) {
53 // A raw array buffer was passed. 88 // A raw array buffer was passed.
54 Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source); 89 Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(source);
55 ArrayBuffer::Contents contents = buffer->GetContents(); 90 ArrayBuffer::Contents contents = buffer->GetContents();
56 91
57 start = reinterpret_cast<const byte*>(contents.Data()); 92 start = reinterpret_cast<const byte*>(contents.Data());
58 end = start + contents.ByteLength(); 93 end = start + contents.ByteLength();
59 94
60 } else if (source->IsTypedArray()) { 95 } else if (source->IsTypedArray()) {
61 // A TypedArray was passed. 96 // A TypedArray was passed.
62 Local<TypedArray> array = Local<TypedArray>::Cast(source); 97 Local<TypedArray> array = Local<TypedArray>::Cast(source);
63 Local<ArrayBuffer> buffer = array->Buffer(); 98 Local<ArrayBuffer> buffer = array->Buffer();
64 99
65 ArrayBuffer::Contents contents = buffer->GetContents(); 100 ArrayBuffer::Contents contents = buffer->GetContents();
66 101
67 start = 102 start =
68 reinterpret_cast<const byte*>(contents.Data()) + array->ByteOffset(); 103 reinterpret_cast<const byte*>(contents.Data()) + array->ByteOffset();
69 end = start + array->ByteLength(); 104 end = start + array->ByteLength();
70 105
71 } else { 106 } else {
72 thrower->TypeError("Argument 0 must be a buffer source"); 107 thrower->TypeError("Argument 0 must be a buffer source");
73 } 108 }
74 if (start == nullptr || end == start) { 109 if (start == nullptr || end == start) {
75 thrower->CompileError("BufferSource argument is empty"); 110 thrower->CompileError("BufferSource argument is empty");
76 } 111 }
77 return {start, end}; 112 // TODO(titzer): use the handle as well?
113 return i::wasm::ModuleWireBytes(start, end);
78 } 114 }
79 115
80 static i::MaybeHandle<i::WasmModuleObject> CreateModuleObject( 116 i::MaybeHandle<i::JSReceiver> GetSecondArgumentAsImports(
81 v8::Isolate* isolate, const v8::Local<v8::Value> source, 117 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
82 ErrorThrower* thrower) { 118 i::MaybeHandle<i::WasmModuleObject> nothing;
83 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 119 if (args.Length() < 2) return nothing;
84 i::MaybeHandle<i::JSObject> nothing; 120 if (args[1]->IsUndefined()) return nothing;
85 121
86 RawBuffer buffer = GetRawBufferSource(source, thrower); 122 if (!args[1]->IsObject()) {
ahaas 2017/02/17 12:19:04 Independent question: why is this function called
titzer 2017/02/17 13:17:53 Don't have an answer to that :-/
87 if (buffer.start == nullptr) return i::MaybeHandle<i::WasmModuleObject>(); 123 thrower->TypeError("Argument 1 must be an object");
88 124 return nothing;
89 DCHECK(source->IsArrayBuffer() || source->IsTypedArray()); 125 }
90 return i::wasm::CreateModuleObjectFromBytes( 126 Local<Object> obj = Local<Object>::Cast(args[1]);
91 i_isolate, buffer.start, buffer.end, thrower, i::wasm::kWasmOrigin, 127 return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
92 i::Handle<i::Script>::null(), i::Vector<const byte>::empty());
93 } 128 }
94 129
95 static bool ValidateModule(v8::Isolate* isolate, 130 // WebAssembly.compile(bytes) -> Promise
96 const v8::Local<v8::Value> source,
97 ErrorThrower* thrower) {
98 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
99 i::MaybeHandle<i::JSObject> nothing;
100
101 RawBuffer buffer = GetRawBufferSource(source, thrower);
102 if (buffer.start == nullptr) return false;
103
104 DCHECK(source->IsArrayBuffer() || source->IsTypedArray());
105 return i::wasm::ValidateModuleBytes(i_isolate, buffer.start, buffer.end,
106 thrower,
107 i::wasm::ModuleOrigin::kWasmOrigin);
108 }
109
110 // TODO(wasm): move brand check to the respective types, and don't throw
111 // in it, rather, use a provided ErrorThrower, or let caller handle it.
112 static bool HasBrand(i::Handle<i::Object> value, i::Handle<i::Symbol> sym) {
113 if (!value->IsJSObject()) return false;
114 i::Handle<i::JSObject> object = i::Handle<i::JSObject>::cast(value);
115 Maybe<bool> has_brand = i::JSObject::HasOwnProperty(object, sym);
116 return !has_brand.IsNothing() && has_brand.ToChecked();
117 }
118
119 static bool BrandCheck(ErrorThrower* thrower, i::Handle<i::Object> value,
120 i::Handle<i::Symbol> sym, const char* msg) {
121 return HasBrand(value, sym) ? true : (thrower->TypeError("%s", msg), false);
122 }
123
124 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) { 131 void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
ahaas 2017/02/17 12:19:04 I would prefer a function name which refers to the
titzer 2017/02/17 13:17:53 The name here is chosen to reflect the JavaScript
125 v8::Isolate* isolate = args.GetIsolate(); 132 v8::Isolate* isolate = args.GetIsolate();
133 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
126 HandleScope scope(isolate); 134 HandleScope scope(isolate);
127 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate), 135 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
128 "WebAssembly.compile()"); 136 "WebAssembly.compile()");
129 137
130 Local<Context> context = isolate->GetCurrentContext(); 138 Local<Context> context = isolate->GetCurrentContext();
131 v8::Local<v8::Promise::Resolver> resolver; 139 v8::Local<v8::Promise::Resolver> resolver;
132 if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return; 140 if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return;
133 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 141 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
134 return_value.Set(resolver->GetPromise()); 142 return_value.Set(resolver->GetPromise());
135 143
136 if (args.Length() < 1) { 144 auto bytes = GetFirstArgumentAsBytes(args, &thrower);
137 thrower.TypeError("Argument 0 must be a buffer source"); 145 if (thrower.error()) {
138 resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 146 resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
139 return; 147 return;
140 } 148 }
141 i::MaybeHandle<i::JSObject> module_obj = 149 i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise());
142 CreateModuleObject(isolate, args[0], &thrower); 150 i::wasm::AsyncCompile(i_isolate, promise, bytes);
143
144 if (thrower.error()) {
145 resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
146 } else {
147 resolver->Resolve(context, Utils::ToLocal(module_obj.ToHandleChecked()));
148 }
149 } 151 }
150 152
153 // WebAssembly.validate(bytes) -> bool
151 void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) { 154 void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
152 v8::Isolate* isolate = args.GetIsolate(); 155 v8::Isolate* isolate = args.GetIsolate();
153 HandleScope scope(isolate); 156 HandleScope scope(isolate);
154 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate), 157 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
155 "WebAssembly.validate()"); 158 "WebAssembly.validate()");
156 159
157 if (args.Length() < 1) { 160 auto bytes = GetFirstArgumentAsBytes(args, &thrower);
158 thrower.TypeError("Argument 0 must be a buffer source");
159 return;
160 }
161 161
162 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 162 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
163 if (ValidateModule(isolate, args[0], &thrower)) { 163 if (!thrower.error() &&
164 i::wasm::SyncValidate(reinterpret_cast<i::Isolate*>(isolate), &thrower,
165 bytes)) {
164 return_value.Set(v8::True(isolate)); 166 return_value.Set(v8::True(isolate));
165 } else { 167 } else {
166 if (thrower.wasm_error()) thrower.Reify(); // Clear error. 168 if (thrower.wasm_error()) thrower.Reify(); // Clear error.
167 return_value.Set(v8::False(isolate)); 169 return_value.Set(v8::False(isolate));
168 } 170 }
169 } 171 }
170 172
173 // new WebAssembly.Module(bytes) -> WebAssembly.Module
171 void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) { 174 void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
ahaas 2017/02/17 12:19:04 And a name which points to the synchronous nature
titzer 2017/02/17 13:17:53 Same as above. It's named to reflect the JS API.
172 v8::Isolate* isolate = args.GetIsolate(); 175 v8::Isolate* isolate = args.GetIsolate();
176 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
173 HandleScope scope(isolate); 177 HandleScope scope(isolate);
Clemens Hammacher 2017/02/16 20:36:57 What does this line do? It's also not clang-format
titzer 2017/02/17 13:17:53 Not sure which line you mean, as the lines seem pr
Clemens Hammacher 2017/02/17 13:54:05 Never mind, Rietviel was missing some lines when s
174 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate), 178 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
175 "WebAssembly.Module()"); 179 "WebAssembly.Module()");
176 180
177 if (args.Length() < 1) { 181 auto bytes = GetFirstArgumentAsBytes(args, &thrower);
178 thrower.TypeError("Argument 0 must be a buffer source"); 182 if (thrower.error()) return;
179 return;
180 }
181 183
182 i::MaybeHandle<i::JSObject> module_obj = 184 i::MaybeHandle<i::Object> module_obj =
183 CreateModuleObject(isolate, args[0], &thrower); 185 i::wasm::SyncCompile(i_isolate, &thrower, bytes);
184 if (module_obj.is_null()) return; 186 if (module_obj.is_null()) return;
185 187
186 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 188 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
187 return_value.Set(Utils::ToLocal(module_obj.ToHandleChecked())); 189 return_value.Set(Utils::ToLocal(module_obj.ToHandleChecked()));
188 } 190 }
189 191
190 MaybeLocal<Value> InstantiateModuleImpl( 192 // WebAssembly.Module.imports(module) -> Array<Import>
191 i::Isolate* i_isolate, i::Handle<i::WasmModuleObject> i_module_obj,
192 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
193 // It so happens that in both the WebAssembly.instantiate, as well as
194 // WebAssembly.Instance ctor, the positions of the ffi object and memory
195 // are the same. If that changes later, we refactor the consts into
196 // parameters.
197 static const int kFfiOffset = 1;
198
199 MaybeLocal<Value> nothing;
200 i::Handle<i::JSReceiver> ffi = i::Handle<i::JSObject>::null();
201 // This is a first - level validation of the argument. If present, we only
202 // check its type. {Instantiate} will further check that if the module
203 // has imports, the argument must be present, as well as piecemeal
204 // import satisfaction.
205 if (args.Length() > kFfiOffset && !args[kFfiOffset]->IsUndefined()) {
206 if (!args[kFfiOffset]->IsObject()) {
207 thrower->TypeError("Argument %d must be an object", kFfiOffset);
208 return nothing;
209 }
210 Local<Object> obj = Local<Object>::Cast(args[kFfiOffset]);
211 ffi = i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
212 }
213
214 i::MaybeHandle<i::JSObject> instance =
215 i::wasm::WasmModule::Instantiate(i_isolate, thrower, i_module_obj, ffi);
216 if (instance.is_null()) {
217 if (!thrower->error())
218 thrower->RuntimeError("Could not instantiate module");
219 return nothing;
220 }
221 DCHECK(!i_isolate->has_pending_exception());
222 return Utils::ToLocal(instance.ToHandleChecked());
223 }
224
225 namespace {
226 i::MaybeHandle<i::WasmModuleObject> GetFirstArgumentAsModule(
227 const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) {
228 v8::Isolate* isolate = args.GetIsolate();
229 i::MaybeHandle<i::WasmModuleObject> nothing;
230 if (args.Length() < 1) {
231 thrower->TypeError("Argument 0 must be a WebAssembly.Module");
232 return nothing;
233 }
234
235 Local<Context> context = isolate->GetCurrentContext();
236 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
237 if (!BrandCheck(thrower, Utils::OpenHandle(*args[0]),
238 i::Handle<i::Symbol>(i_context->wasm_module_sym()),
239 "Argument 0 must be a WebAssembly.Module")) {
240 return nothing;
241 }
242
243 Local<Object> module_obj = Local<Object>::Cast(args[0]);
244 return i::Handle<i::WasmModuleObject>::cast(
245 v8::Utils::OpenHandle(*module_obj));
246 }
247 } // namespace
248
249 void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) { 193 void WebAssemblyModuleImports(const v8::FunctionCallbackInfo<v8::Value>& args) {
250 HandleScope scope(args.GetIsolate()); 194 HandleScope scope(args.GetIsolate());
251 v8::Isolate* isolate = args.GetIsolate(); 195 v8::Isolate* isolate = args.GetIsolate();
252 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 196 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
253 ErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()"); 197 ErrorThrower thrower(i_isolate, "WebAssembly.Module.imports()");
254 198
255 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); 199 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
256 200 if (thrower.error()) return;
ahaas 2017/02/17 12:19:04 Is it okay that the actual error reason is lost he
titzer 2017/02/17 13:17:53 The destructor of ErrorThrower will schedule it to
257 if (!maybe_module.is_null()) { 201 auto imports = i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
258 auto imports = 202 args.GetReturnValue().Set(Utils::ToLocal(imports));
259 i::wasm::GetImports(i_isolate, maybe_module.ToHandleChecked());
260 args.GetReturnValue().Set(Utils::ToLocal(imports));
261 }
262 } 203 }
263 204
205 // WebAssembly.Module.imports(module) -> Array<Export>
Clemens Hammacher 2017/02/16 20:36:57 exports, not imports.
titzer 2017/02/17 13:17:53 Done.
264 void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) { 206 void WebAssemblyModuleExports(const v8::FunctionCallbackInfo<v8::Value>& args) {
265 HandleScope scope(args.GetIsolate()); 207 HandleScope scope(args.GetIsolate());
266 v8::Isolate* isolate = args.GetIsolate(); 208 v8::Isolate* isolate = args.GetIsolate();
267 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 209 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
268 ErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()"); 210 ErrorThrower thrower(i_isolate, "WebAssembly.Module.exports()");
269 211
270 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); 212 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
271 213 if (thrower.error()) return;
ahaas 2017/02/17 12:19:04 same here.
titzer 2017/02/17 13:17:53 Acknowledged.
272 if (!maybe_module.is_null()) { 214 auto exports = i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
273 auto exports = 215 args.GetReturnValue().Set(Utils::ToLocal(exports));
274 i::wasm::GetExports(i_isolate, maybe_module.ToHandleChecked());
275 args.GetReturnValue().Set(Utils::ToLocal(exports));
276 }
277 } 216 }
278 217
218 // WebAssembly.Module.customSections(module, name) -> Array<Section>
279 void WebAssemblyModuleCustomSections( 219 void WebAssemblyModuleCustomSections(
280 const v8::FunctionCallbackInfo<v8::Value>& args) { 220 const v8::FunctionCallbackInfo<v8::Value>& args) {
281 HandleScope scope(args.GetIsolate()); 221 HandleScope scope(args.GetIsolate());
282 v8::Isolate* isolate = args.GetIsolate(); 222 v8::Isolate* isolate = args.GetIsolate();
283 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 223 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
284 ErrorThrower thrower(i_isolate, "WebAssembly.Module.customSections()"); 224 ErrorThrower thrower(i_isolate, "WebAssembly.Module.customSections()");
285 225
286 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); 226 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
227 if (thrower.error()) return;
287 228
288 if (args.Length() < 2) { 229 if (args.Length() < 2) {
289 thrower.TypeError("Argument 1 must be a string"); 230 thrower.TypeError("Argument 1 must be a string");
290 return; 231 return;
291 } 232 }
292 233
293 i::Handle<i::Object> name = Utils::OpenHandle(*args[1]); 234 i::Handle<i::Object> name = Utils::OpenHandle(*args[1]);
294 if (!name->IsString()) { 235 if (!name->IsString()) {
295 thrower.TypeError("Argument 1 must be a string"); 236 thrower.TypeError("Argument 1 must be a string");
296 return; 237 return;
297 } 238 }
298 239
299 if (!maybe_module.is_null()) { 240 auto custom_sections =
300 auto custom_sections = 241 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(),
301 i::wasm::GetCustomSections(i_isolate, maybe_module.ToHandleChecked(), 242 i::Handle<i::String>::cast(name), &thrower);
302 i::Handle<i::String>::cast(name), &thrower); 243 if (!thrower.error()) {
Clemens Hammacher 2017/02/16 20:36:57 "if (thrower.error()) return;" would be more consi
titzer 2017/02/17 13:17:53 Done.
303 if (!thrower.error()) { 244 args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
304 args.GetReturnValue().Set(Utils::ToLocal(custom_sections));
305 }
306 } 245 }
307 } 246 }
308 247
248 // new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
309 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) { 249 void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
310 HandleScope scope(args.GetIsolate()); 250 HandleScope scope(args.GetIsolate());
311 v8::Isolate* isolate = args.GetIsolate(); 251 v8::Isolate* isolate = args.GetIsolate();
312 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 252 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
313 ErrorThrower thrower(i_isolate, "WebAssembly.Instance()"); 253 ErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
314 254
315 auto maybe_module = GetFirstArgumentAsModule(args, &thrower); 255 auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
256 if (thrower.error()) return;
316 257
317 if (!maybe_module.is_null()) { 258 auto maybe_imports = GetSecondArgumentAsImports(args, &thrower);
318 MaybeLocal<Value> instance = InstantiateModuleImpl( 259 if (thrower.error()) return;
319 i_isolate, maybe_module.ToHandleChecked(), args, &thrower);
320 260
321 if (instance.IsEmpty()) { 261 i::MaybeHandle<i::Object> instance_object = i::wasm::SyncInstantiate(
322 DCHECK(thrower.error()); 262 i_isolate, &thrower, maybe_module.ToHandleChecked(), maybe_imports,
323 return; 263 i::MaybeHandle<i::JSArrayBuffer>());
324 } 264 if (!instance_object.is_null()) {
Clemens Hammacher 2017/02/16 20:36:57 if (thrower.error()) return;
titzer 2017/02/17 13:17:53 Done.
325 args.GetReturnValue().Set(instance.ToLocalChecked()); 265 args.GetReturnValue().Set(
266 Utils::ToLocal(instance_object.ToHandleChecked()));
326 } 267 }
327 } 268 }
328 269
270 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
271 // WebAssembly.instantiate(bytes, imports) -> {WebAssembly.Module,
272 // WebAssembly.Instance}
Clemens Hammacher 2017/02/16 20:36:57 That line break is annoying. Can you indent it a b
titzer 2017/02/17 13:17:53 Done.
329 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) { 273 void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
330 v8::Isolate* isolate = args.GetIsolate(); 274 v8::Isolate* isolate = args.GetIsolate();
331 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 275 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
332 ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()"); 276 ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()");
333 277
334 HandleScope scope(isolate); 278 HandleScope scope(isolate);
335 279
336 Local<Context> context = isolate->GetCurrentContext(); 280 Local<Context> context = isolate->GetCurrentContext();
337 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 281 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
338 282
(...skipping 10 matching lines...) Expand all
349 return; 293 return;
350 } 294 }
351 295
352 i::Handle<i::Object> first_arg = Utils::OpenHandle(*args[0]); 296 i::Handle<i::Object> first_arg = Utils::OpenHandle(*args[0]);
353 if (!first_arg->IsJSObject()) { 297 if (!first_arg->IsJSObject()) {
354 thrower.TypeError( 298 thrower.TypeError(
355 "Argument 0 must be a buffer source or a WebAssembly.Module object"); 299 "Argument 0 must be a buffer source or a WebAssembly.Module object");
356 resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 300 resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
357 return; 301 return;
358 } 302 }
359 bool want_pair = 303
360 !HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym())); 304 auto maybe_imports = GetSecondArgumentAsImports(args, &thrower);
361 i::Handle<i::WasmModuleObject> module_obj; 305 if (thrower.error()) {
362 if (want_pair) { 306 resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
363 i::MaybeHandle<i::WasmModuleObject> maybe_module_obj = 307 return;
364 CreateModuleObject(isolate, args[0], &thrower); 308 }
365 if (!maybe_module_obj.ToHandle(&module_obj)) { 309 i::Handle<i::JSPromise> promise = Utils::OpenHandle(*resolver->GetPromise());
366 DCHECK(thrower.error()); 310
311 if (HasBrand(first_arg, i::Handle<i::Symbol>(i_context->wasm_module_sym()))) {
312 // WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
313 auto module_object = GetFirstArgumentAsModule(args, &thrower);
314 i::wasm::AsyncInstantiate(i_isolate, promise,
315 module_object.ToHandleChecked(), maybe_imports);
316 } else {
317 // WebAssembly.instantiate(bytes, imports) -> {module, instance}
318 auto bytes = GetFirstArgumentAsBytes(args, &thrower);
319 if (thrower.error()) {
367 resolver->Reject(context, Utils::ToLocal(thrower.Reify())); 320 resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
368 return; 321 return;
369 } 322 }
370 } else { 323 i::wasm::AsyncCompileAndInstantiate(i_isolate, promise, bytes, nullptr,
371 module_obj = i::Handle<i::WasmModuleObject>::cast(first_arg); 324 maybe_imports);
372 }
373 DCHECK(!module_obj.is_null());
374 MaybeLocal<Value> instance =
375 InstantiateModuleImpl(i_isolate, module_obj, args, &thrower);
376 if (instance.IsEmpty()) {
377 DCHECK(thrower.error());
378 resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
379 } else {
380 DCHECK(!thrower.error());
381 Local<Value> retval;
382 if (want_pair) {
383 i::Handle<i::JSFunction> object_function = i::Handle<i::JSFunction>(
384 i_isolate->native_context()->object_function(), i_isolate);
385
386 i::Handle<i::JSObject> i_retval =
387 i_isolate->factory()->NewJSObject(object_function, i::TENURED);
388 i::Handle<i::String> module_property_name =
389 i_isolate->factory()->InternalizeUtf8String("module");
390 i::Handle<i::String> instance_property_name =
391 i_isolate->factory()->InternalizeUtf8String("instance");
392 i::JSObject::AddProperty(i_retval, module_property_name, module_obj,
393 i::NONE);
394 i::JSObject::AddProperty(i_retval, instance_property_name,
395 Utils::OpenHandle(*instance.ToLocalChecked()),
396 i::NONE);
397 retval = Utils::ToLocal(i_retval);
398 } else {
399 retval = instance.ToLocalChecked();
400 }
401 DCHECK(!retval.IsEmpty());
402 resolver->Resolve(context, retval);
403 } 325 }
404 } 326 }
405 327
406 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower, 328 bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
407 Local<Context> context, Local<v8::Object> object, 329 Local<Context> context, Local<v8::Object> object,
408 Local<String> property, int* result, 330 Local<String> property, int* result,
409 int64_t lower_bound, uint64_t upper_bound) { 331 int64_t lower_bound, uint64_t upper_bound) {
410 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property); 332 v8::MaybeLocal<v8::Value> maybe = object->Get(context, property);
411 v8::Local<v8::Value> value; 333 v8::Local<v8::Value> value;
412 if (maybe.ToLocal(&value)) { 334 if (maybe.ToLocal(&value)) {
(...skipping 10 matching lines...) Expand all
423 " is above the upper bound %" PRIu64, 345 " is above the upper bound %" PRIu64,
424 number, upper_bound); 346 number, upper_bound);
425 return false; 347 return false;
426 } 348 }
427 *result = static_cast<int>(number); 349 *result = static_cast<int>(number);
428 return true; 350 return true;
429 } 351 }
430 return false; 352 return false;
431 } 353 }
432 354
355 // new WebAssembly.Table(args) -> WebAssembly.Table
433 void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { 356 void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
434 v8::Isolate* isolate = args.GetIsolate(); 357 v8::Isolate* isolate = args.GetIsolate();
435 HandleScope scope(isolate); 358 HandleScope scope(isolate);
436 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate), 359 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
437 "WebAssembly.Module()"); 360 "WebAssembly.Module()");
438 if (args.Length() < 1 || !args[0]->IsObject()) { 361 if (args.Length() < 1 || !args[0]->IsObject()) {
439 thrower.TypeError("Argument 0 must be a table descriptor"); 362 thrower.TypeError("Argument 0 must be a table descriptor");
440 return; 363 return;
441 } 364 }
442 Local<Context> context = isolate->GetCurrentContext(); 365 Local<Context> context = isolate->GetCurrentContext();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 i::Handle<i::Symbol>(i_context->wasm_table_sym()), 462 i::Handle<i::Symbol>(i_context->wasm_table_sym()),
540 "Receiver is not a WebAssembly.Table")) { 463 "Receiver is not a WebAssembly.Table")) {
541 return; 464 return;
542 } 465 }
543 auto receiver = 466 auto receiver =
544 i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This())); 467 i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));
545 args.GetReturnValue().Set( 468 args.GetReturnValue().Set(
546 v8::Number::New(isolate, receiver->current_length())); 469 v8::Number::New(isolate, receiver->current_length()));
547 } 470 }
548 471
472 // WebAssembly.Table.grow(num) -> num
549 void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) { 473 void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
550 v8::Isolate* isolate = args.GetIsolate(); 474 v8::Isolate* isolate = args.GetIsolate();
551 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate), 475 ErrorThrower thrower(reinterpret_cast<i::Isolate*>(isolate),
552 "WebAssembly.Table.grow()"); 476 "WebAssembly.Table.grow()");
553 Local<Context> context = isolate->GetCurrentContext(); 477 Local<Context> context = isolate->GetCurrentContext();
554 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 478 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
555 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()), 479 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
556 i::Handle<i::Symbol>(i_context->wasm_table_sym()), 480 i::Handle<i::Symbol>(i_context->wasm_table_sym()),
557 "Receiver is not a WebAssembly.Table")) { 481 "Receiver is not a WebAssembly.Table")) {
558 return; 482 return;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 i::Object* null = i_isolate->heap()->null_value(); 516 i::Object* null = i_isolate->heap()->null_value();
593 for (int i = old_size; i < new_size; ++i) new_array->set(i, null); 517 for (int i = old_size; i < new_size; ++i) new_array->set(i, null);
594 receiver->set_functions(*new_array); 518 receiver->set_functions(*new_array);
595 } 519 }
596 520
597 // TODO(gdeepti): use weak links for instances 521 // TODO(gdeepti): use weak links for instances
598 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 522 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
599 return_value.Set(old_size); 523 return_value.Set(old_size);
600 } 524 }
601 525
526 // WebAssembly.Table.get(num) -> JSFunction
602 void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) { 527 void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
603 v8::Isolate* isolate = args.GetIsolate(); 528 v8::Isolate* isolate = args.GetIsolate();
604 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 529 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
605 ErrorThrower thrower(i_isolate, "WebAssembly.Table.get()"); 530 ErrorThrower thrower(i_isolate, "WebAssembly.Table.get()");
606 Local<Context> context = isolate->GetCurrentContext(); 531 Local<Context> context = isolate->GetCurrentContext();
607 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 532 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
608 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()), 533 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
609 i::Handle<i::Symbol>(i_context->wasm_table_sym()), 534 i::Handle<i::Symbol>(i_context->wasm_table_sym()),
610 "Receiver is not a WebAssembly.Table")) { 535 "Receiver is not a WebAssembly.Table")) {
611 return; 536 return;
612 } 537 }
613 538
614 auto receiver = 539 auto receiver =
615 i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This())); 540 i::Handle<i::WasmTableObject>::cast(Utils::OpenHandle(*args.This()));
616 i::Handle<i::FixedArray> array(receiver->functions(), i_isolate); 541 i::Handle<i::FixedArray> array(receiver->functions(), i_isolate);
617 int i = 0; 542 int i = 0;
618 if (args.Length() > 0 && !args[0]->Int32Value(context).To(&i)) return; 543 if (args.Length() > 0 && !args[0]->Int32Value(context).To(&i)) return;
619 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 544 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
620 if (i < 0 || i >= array->length()) { 545 if (i < 0 || i >= array->length()) {
621 thrower.RangeError("index out of bounds"); 546 thrower.RangeError("index out of bounds");
622 return; 547 return;
623 } 548 }
624 549
625 i::Handle<i::Object> value(array->get(i), i_isolate); 550 i::Handle<i::Object> value(array->get(i), i_isolate);
626 return_value.Set(Utils::ToLocal(value)); 551 return_value.Set(Utils::ToLocal(value));
627 } 552 }
628 553
554 // WebAssembly.Table.set(num, JSFunction)
629 void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) { 555 void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
630 v8::Isolate* isolate = args.GetIsolate(); 556 v8::Isolate* isolate = args.GetIsolate();
631 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 557 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
632 ErrorThrower thrower(i_isolate, "WebAssembly.Table.set()"); 558 ErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
633 Local<Context> context = isolate->GetCurrentContext(); 559 Local<Context> context = isolate->GetCurrentContext();
634 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 560 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
635 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()), 561 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
636 i::Handle<i::Symbol>(i_context->wasm_table_sym()), 562 i::Handle<i::Symbol>(i_context->wasm_table_sym()),
637 "Receiver is not a WebAssembly.Table")) { 563 "Receiver is not a WebAssembly.Table")) {
638 return; 564 return;
(...skipping 27 matching lines...) Expand all
666 i::wasm::UpdateDispatchTables(i_isolate, dispatch_tables, i, 592 i::wasm::UpdateDispatchTables(i_isolate, dispatch_tables, i,
667 i::Handle<i::JSFunction>::null()); 593 i::Handle<i::JSFunction>::null());
668 } else { 594 } else {
669 i::wasm::UpdateDispatchTables(i_isolate, dispatch_tables, i, 595 i::wasm::UpdateDispatchTables(i_isolate, dispatch_tables, i,
670 i::Handle<i::JSFunction>::cast(value)); 596 i::Handle<i::JSFunction>::cast(value));
671 } 597 }
672 598
673 i::Handle<i::FixedArray>::cast(array)->set(i, *value); 599 i::Handle<i::FixedArray>::cast(array)->set(i, *value);
674 } 600 }
675 601
602 // WebAssembly.Memory.grow(num) -> num
676 void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) { 603 void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
677 v8::Isolate* isolate = args.GetIsolate(); 604 v8::Isolate* isolate = args.GetIsolate();
678 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 605 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
679 ErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()"); 606 ErrorThrower thrower(i_isolate, "WebAssembly.Memory.grow()");
680 Local<Context> context = isolate->GetCurrentContext(); 607 Local<Context> context = isolate->GetCurrentContext();
681 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 608 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
682 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()), 609 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
683 i::Handle<i::Symbol>(i_context->wasm_memory_sym()), 610 i::Handle<i::Symbol>(i_context->wasm_memory_sym()),
684 "Receiver is not a WebAssembly.Memory")) { 611 "Receiver is not a WebAssembly.Memory")) {
685 return; 612 return;
(...skipping 22 matching lines...) Expand all
708 int32_t ret = i::wasm::GrowWebAssemblyMemory( 635 int32_t ret = i::wasm::GrowWebAssemblyMemory(
709 i_isolate, receiver, static_cast<uint32_t>(delta_size)); 636 i_isolate, receiver, static_cast<uint32_t>(delta_size));
710 if (ret == -1) { 637 if (ret == -1) {
711 thrower.RangeError("Unable to grow instance memory."); 638 thrower.RangeError("Unable to grow instance memory.");
712 return; 639 return;
713 } 640 }
714 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); 641 v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
715 return_value.Set(ret); 642 return_value.Set(ret);
716 } 643 }
717 644
645 // WebAssembly.Memory.buffer -> ArrayBuffer
718 void WebAssemblyMemoryGetBuffer( 646 void WebAssemblyMemoryGetBuffer(
719 const v8::FunctionCallbackInfo<v8::Value>& args) { 647 const v8::FunctionCallbackInfo<v8::Value>& args) {
720 v8::Isolate* isolate = args.GetIsolate(); 648 v8::Isolate* isolate = args.GetIsolate();
721 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 649 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
722 ErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer"); 650 ErrorThrower thrower(i_isolate, "WebAssembly.Memory.buffer");
723 Local<Context> context = isolate->GetCurrentContext(); 651 Local<Context> context = isolate->GetCurrentContext();
724 i::Handle<i::Context> i_context = Utils::OpenHandle(*context); 652 i::Handle<i::Context> i_context = Utils::OpenHandle(*context);
725 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()), 653 if (!BrandCheck(&thrower, Utils::OpenHandle(*args.This()),
726 i::Handle<i::Symbol>(i_context->wasm_memory_sym()), 654 i::Handle<i::Symbol>(i_context->wasm_memory_sym()),
727 "Receiver is not a WebAssembly.Memory")) { 655 "Receiver is not a WebAssembly.Memory")) {
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate); 863 i::Handle<i::Symbol> symbol(isolate->context()->wasm_memory_sym(), isolate);
936 return HasBrand(value, symbol); 864 return HasBrand(value, symbol);
937 } 865 }
938 866
939 bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) { 867 bool WasmJs::IsWasmTableObject(Isolate* isolate, Handle<Object> value) {
940 i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate); 868 i::Handle<i::Symbol> symbol(isolate->context()->wasm_table_sym(), isolate);
941 return HasBrand(value, symbol); 869 return HasBrand(value, symbol);
942 } 870 }
943 } // namespace internal 871 } // namespace internal
944 } // namespace v8 872 } // namespace v8
OLDNEW
« no previous file with comments | « src/value-serializer.cc ('k') | src/wasm/wasm-module.h » ('j') | src/wasm/wasm-module.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698