v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
module-decoder.cc
Go to the documentation of this file.
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
3// found in the LICENSE file.
4
6
10#include "src/wasm/decoder.h"
17
18namespace v8 {
19namespace internal {
20namespace wasm {
21
22const char* SectionName(SectionCode code) {
23 switch (code) {
25 return "Unknown";
27 return "Type";
29 return "Import";
31 return "Function";
33 return "Table";
35 return "Memory";
37 return "Global";
39 return "Export";
41 return "Start";
43 return "Code";
45 return "Element";
47 return "Data";
48 case kTagSectionCode:
49 return "Tag";
51 return "StringRef";
53 return "DataCount";
55 return kNameString;
59 return kDebugInfoString;
63 return kBuildIdString;
65 return kInstTraceString;
69 return kBranchHintsString;
70 default:
71 return "<unknown>";
72 }
73}
74
76 WasmEnabledFeatures enabled_features,
77 base::Vector<const uint8_t> wire_bytes, bool validate_functions,
78 ModuleOrigin origin, Counters* counters,
79 std::shared_ptr<metrics::Recorder> metrics_recorder,
80 v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method,
81 WasmDetectedFeatures* detected_features) {
82 if (counters) {
83 auto size_counter =
84 SELECT_WASM_COUNTER(counters, origin, wasm, module_size_bytes);
85 static_assert(kV8MaxWasmModuleSize < kMaxInt);
86 size_counter->AddSample(static_cast<int>(wire_bytes.size()));
87 }
88
91 timer.Start();
93 DecodeWasmModule(enabled_features, wire_bytes, validate_functions, origin,
94 detected_features);
95 if (counters && result.ok()) {
96 auto counter =
97 SELECT_WASM_COUNTER(counters, origin, wasm_functions_per, module);
98 counter->AddSample(
99 static_cast<int>(result.value()->num_declared_functions));
100 }
101
102 // Record event metrics.
103 metrics_event.wall_clock_duration_in_us = timer.Elapsed().InMicroseconds();
104 timer.Stop();
105 metrics_event.success = result.ok();
106 metrics_event.async = decoding_method == DecodingMethod::kAsync ||
107 decoding_method == DecodingMethod::kAsyncStream;
108 metrics_event.streamed = decoding_method == DecodingMethod::kSyncStream ||
109 decoding_method == DecodingMethod::kAsyncStream;
110 if (result.ok()) {
111 metrics_event.function_count = result.value()->num_declared_functions;
112 }
113 metrics_event.module_size_in_bytes = wire_bytes.size();
114 metrics_recorder->DelayMainThreadEvent(metrics_event, context_id);
115
116 return result;
117}
118
121 bool validate_functions, ModuleOrigin origin,
122 WasmDetectedFeatures* detected_features) {
123 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
124 "wasm.DecodeWasmModule");
125 ModuleDecoderImpl decoder{enabled_features, wire_bytes, origin,
126 detected_features};
127 ModuleResult result = decoder.DecodeModule(validate_functions);
128 return result;
129}
130
132 base::Vector<const uint8_t> wire_bytes, ITracer* tracer) {
133 constexpr bool kNoValidateFunctions = false;
134 WasmDetectedFeatures unused_detected_features;
136 &unused_detected_features, tracer};
137 return decoder.DecodeModule(kNoValidateFunctions);
138}
139
141 WasmDetectedFeatures* detected_features)
142 : impl_(std::make_unique<ModuleDecoderImpl>(
143 enabled_features, base::Vector<const uint8_t>{}, kWasmOrigin,
144 detected_features)) {}
145
147
148const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
149 return impl_->shared_module();
150}
151
153 impl_->DecodeModuleHeader(bytes);
154}
155
158 uint32_t offset) {
159 impl_->DecodeSection(section_code, bytes, offset);
160}
161
162void ModuleDecoder::DecodeFunctionBody(uint32_t index, uint32_t length,
163 uint32_t offset) {
164 impl_->DecodeFunctionBody(index, length, offset);
165}
166
168 impl_->StartCodeSection(section_bytes);
169}
170
171bool ModuleDecoder::CheckFunctionsCount(uint32_t functions_count,
172 uint32_t error_offset) {
173 return impl_->CheckFunctionsCount(functions_count, error_offset);
174}
175
176ModuleResult ModuleDecoder::FinishDecoding() { return impl_->FinishDecoding(); }
177
180 uint32_t offset,
182 if (!decoder->ok()) return 0;
183 decoder->impl_->Reset(bytes, offset);
184 *result =
186 return decoder->impl_->pc() - bytes.begin();
187}
188
189bool ModuleDecoder::ok() const { return impl_->ok(); }
190
192 WasmEnabledFeatures enabled_features, Zone* zone,
194 WasmDetectedFeatures unused_detected_features;
195 ModuleDecoderImpl decoder{enabled_features, bytes, kWasmOrigin,
196 &unused_detected_features};
197 return decoder.toResult(
198 decoder.DecodeFunctionSignatureForTesting(zone, bytes.begin()));
199}
200
202 WasmEnabledFeatures enabled_features, base::Vector<const uint8_t> bytes,
203 ValueType expected) {
204 WasmDetectedFeatures unused_detected_features;
205 ModuleDecoderImpl decoder{enabled_features, bytes, kWasmOrigin,
206 &unused_detected_features};
207 return decoder.DecodeInitExprForTesting(expected);
208}
209
211 WasmEnabledFeatures enabled_features, Zone* zone,
212 ModuleWireBytes wire_bytes, const WasmModule* module,
213 base::Vector<const uint8_t> function_bytes) {
214 if (function_bytes.size() > kV8MaxWasmFunctionSize) {
215 return FunctionResult{
216 WasmError{0, "size > maximum function size (%zu): %zu",
217 kV8MaxWasmFunctionSize, function_bytes.size()}};
218 }
219 WasmDetectedFeatures unused_detected_features;
220 ModuleDecoderImpl decoder{enabled_features, function_bytes, kWasmOrigin,
221 &unused_detected_features};
222 return decoder.DecodeSingleFunctionForTesting(zone, wire_bytes, module);
223}
224
226 base::Vector<const uint8_t> encoded_offsets) {
227 std::vector<AsmJsOffsetFunctionEntries> functions;
228
229 Decoder decoder(encoded_offsets);
230 uint32_t functions_count = decoder.consume_u32v("functions count");
231 // Consistency check.
232 DCHECK_GE(encoded_offsets.size(), functions_count);
233 functions.reserve(functions_count);
234
235 for (uint32_t i = 0; i < functions_count; ++i) {
236 uint32_t size = decoder.consume_u32v("table size");
237 if (size == 0) {
238 functions.emplace_back();
239 continue;
240 }
241 DCHECK(decoder.checkAvailable(size));
242 const uint8_t* table_end = decoder.pc() + size;
243 uint32_t locals_size = decoder.consume_u32v("locals size");
244 int function_start_position = decoder.consume_u32v("function start pos");
245 int function_end_position = function_start_position;
246 int last_byte_offset = locals_size;
247 int last_asm_position = function_start_position;
248 std::vector<AsmJsOffsetEntry> func_asm_offsets;
249 func_asm_offsets.reserve(size / 4); // conservative estimation
250 // Add an entry for the stack check, associated with position 0.
251 func_asm_offsets.push_back(
252 {0, function_start_position, function_start_position});
253 while (decoder.pc() < table_end) {
254 DCHECK(decoder.ok());
255 last_byte_offset += decoder.consume_u32v("byte offset delta");
256 int call_position =
257 last_asm_position + decoder.consume_i32v("call position delta");
258 int to_number_position =
259 call_position + decoder.consume_i32v("to_number position delta");
260 last_asm_position = to_number_position;
261 if (decoder.pc() == table_end) {
262 // The last entry is the function end marker.
263 DCHECK_EQ(call_position, to_number_position);
264 function_end_position = call_position;
265 } else {
266 func_asm_offsets.push_back(
267 {last_byte_offset, call_position, to_number_position});
268 }
269 }
270 DCHECK_EQ(decoder.pc(), table_end);
271 functions.emplace_back(AsmJsOffsetFunctionEntries{
272 function_start_position, function_end_position,
273 std::move(func_asm_offsets)});
274 }
275 DCHECK(decoder.ok());
276 DCHECK(!decoder.more());
277
278 return decoder.toResult(AsmJsOffsets{std::move(functions)});
279}
280
281std::vector<CustomSectionOffset> DecodeCustomSections(
283 Decoder decoder(bytes);
284 decoder.consume_bytes(4, "wasm magic");
285 decoder.consume_bytes(4, "wasm version");
286
287 std::vector<CustomSectionOffset> result;
288
289 while (decoder.more()) {
290 uint8_t section_code = decoder.consume_u8("section code");
291 uint32_t section_length = decoder.consume_u32v("section length");
292 uint32_t section_start = decoder.pc_offset();
293 if (section_code != 0) {
294 // Skip known sections.
295 decoder.consume_bytes(section_length, "section bytes");
296 continue;
297 }
298 uint32_t name_length = decoder.consume_u32v("name length");
299 uint32_t name_offset = decoder.pc_offset();
300 decoder.consume_bytes(name_length, "section name");
301 uint32_t payload_offset = decoder.pc_offset();
302 if (section_length < (payload_offset - section_start)) {
303 decoder.error("invalid section length");
304 break;
305 }
306 uint32_t payload_length = section_length - (payload_offset - section_start);
307 decoder.consume_bytes(payload_length);
308 if (decoder.failed()) break;
309 result.push_back({{section_start, section_length},
310 {name_offset, name_length},
311 {payload_offset, payload_length}});
312 }
313
314 return result;
315}
316
317namespace {
318
319bool FindNameSection(Decoder* decoder) {
320 static constexpr int kModuleHeaderSize = 8;
321 decoder->consume_bytes(kModuleHeaderSize, "module header");
322
323 WasmSectionIterator section_iter(decoder, ITracer::NoTrace);
324
325 while (decoder->ok() && section_iter.more() &&
326 section_iter.section_code() != kNameSectionCode) {
327 section_iter.advance(true);
328 }
329 if (!section_iter.more()) return false;
330
331 // Reset the decoder to not read beyond the name section end.
332 decoder->Reset(section_iter.payload(), decoder->pc_offset());
333 return true;
334}
335
336enum class EmptyNames : bool { kAllow, kSkip };
337
338void DecodeNameMapInternal(NameMap& target, Decoder& decoder,
339 EmptyNames empty_names = EmptyNames::kSkip) {
340 uint32_t count = decoder.consume_u32v("names count");
341 for (uint32_t i = 0; i < count; i++) {
342 uint32_t index = decoder.consume_u32v("index");
343 WireBytesRef name =
345 if (!decoder.ok()) break;
346 if (index > NameMap::kMaxKey) continue;
347 if (empty_names == EmptyNames::kSkip && name.is_empty()) continue;
348 if (!validate_utf8(&decoder, name)) continue;
349 target.Put(index, name);
350 }
351 target.FinishInitialization();
352}
353
354void DecodeNameMap(NameMap& target, Decoder& decoder,
355 uint32_t subsection_payload_length,
356 EmptyNames empty_names = EmptyNames::kSkip) {
357 if (target.is_set()) {
358 decoder.consume_bytes(subsection_payload_length);
359 return;
360 }
361 DecodeNameMapInternal(target, decoder, empty_names);
362}
363
364void DecodeIndirectNameMap(IndirectNameMap& target, Decoder& decoder,
365 uint32_t subsection_payload_length) {
366 if (target.is_set()) {
367 decoder.consume_bytes(subsection_payload_length);
368 return;
369 }
370 uint32_t outer_count = decoder.consume_u32v("outer count");
371 for (uint32_t i = 0; i < outer_count; ++i) {
372 uint32_t outer_index = decoder.consume_u32v("outer index");
373 // TODO(jkummerow): Should we try to skip only the invalid entry?
374 if (outer_index > IndirectNameMap::kMaxKey) break;
375 NameMap names;
376 DecodeNameMapInternal(names, decoder);
377 target.Put(outer_index, std::move(names));
378 if (!decoder.ok()) break;
379 }
380 target.FinishInitialization();
381}
382
383} // namespace
384
386 NameMap& names) {
387 Decoder decoder(wire_bytes);
388 if (!FindNameSection(&decoder)) return;
389 while (decoder.ok() && decoder.more()) {
390 uint8_t name_type = decoder.consume_u8("name type");
391 if (name_type & 0x80) break; // no varuint7
392
393 uint32_t name_payload_len = decoder.consume_u32v("name payload length");
394 if (!decoder.checkAvailable(name_payload_len)) break;
395
396 if (name_type != NameSectionKindCode::kFunctionCode) {
397 decoder.consume_bytes(name_payload_len, "name subsection payload");
398 continue;
399 }
400 // We need to allow empty function names for spec-conformant stack traces.
401 DecodeNameMapInternal(names, decoder, EmptyNames::kAllow);
402 // The spec allows only one occurrence of each subsection. We could be
403 // more permissive and allow repeated subsections; in that case we'd
404 // have to delay calling {target.FinishInitialization()} on the function
405 // names map until we've seen them all.
406 // For now, we stop decoding after finding the first function names
407 // subsection.
408 return;
409 }
410}
411
412// This follows the decoding logic of DecodeNameMap/DecodeIndirectNameMap, but
413// processes the results differently, according to the needs of canonical
414// type names:
415// - all type indices are canonicalized.
416// - multiple modules' name sections are merged into the output data structures
417// {typenames} and {fieldnames}; existing entries are not overwritten.
418// - all name payloads are copied out of the wire bytes.
420 base::Vector<const uint8_t> wire_bytes, const WasmModule* module,
421 std::vector<base::OwnedVector<char>>& typenames,
422 std::map<uint32_t, std::vector<base::OwnedVector<char>>>& fieldnames,
423 size_t* total_allocated_size) {
424 bool types_done = false;
425 bool fields_done = false;
426 Decoder decoder(wire_bytes);
427 if (!FindNameSection(&decoder)) return;
428 const char* base = reinterpret_cast<const char*>(wire_bytes.begin());
429 while (decoder.ok() && decoder.more()) {
430 uint8_t name_type = decoder.consume_u8("name type");
431 if (name_type & 0x80) break; // no varuint7
432 uint32_t name_payload_len = decoder.consume_u32v("name payload length");
433 if (!decoder.checkAvailable(name_payload_len)) break;
434 if (name_type == NameSectionKindCode::kTypeCode) {
435 if (types_done) {
436 decoder.consume_bytes(name_payload_len, "name subsection payload");
437 continue; // The spec allows only one occurrence.
438 }
439 types_done = true;
440 uint32_t count = decoder.consume_u32v("names count");
441 for (uint32_t i = 0; i < count; i++) {
442 ModuleTypeIndex module_index{decoder.consume_u32v("index")};
443 WireBytesRef name =
445 if (!decoder.ok()) break;
446 if (!module->has_type(module_index)) continue;
447 if (name.is_empty()) continue;
448 CanonicalTypeIndex canonical_index =
449 module->canonical_type_id(module_index);
450 uint32_t index = canonical_index.index;
451 // Callers should have pre-sized the target vector appropriately.
452 DCHECK_LT(index, typenames.size());
453 // TODO(jkummerow): Consider implementing a more refined strategy
454 // for conflict resolution than "first definition wins", if we
455 // encounter that situation in practice. Note that we'll also have
456 // to deal with multiple field names then (in the loop below).
457 if (!typenames[index].empty()) continue; // We already have a name.
458 if (!validate_utf8(&decoder, name)) continue;
459 uint32_t length = name.length();
460 typenames[index] =
462 *total_allocated_size += length;
463 }
464 } else if (name_type == NameSectionKindCode::kFieldCode) {
465 if (fields_done) {
466 decoder.consume_bytes(name_payload_len, "name subsection payload");
467 continue; // The spec allows only one occurrence.
468 }
469 fields_done = true;
470 uint32_t types_count = decoder.consume_u32v("types count");
471 for (uint32_t i = 0; i < types_count; ++i) {
472 ModuleTypeIndex module_index{decoder.consume_u32v("type index")};
473 // TODO(jkummerow): Should we try to skip only the invalid entry?
474 if (!module->has_struct(module_index)) return;
475 CanonicalTypeIndex canonical_index =
476 module->canonical_type_id(module_index);
477 uint32_t struct_index = canonical_index.index;
478 if (struct_index >= typenames.size()) return;
479 // Due to {module->has_struct()}, this is guaranteed to succeed.
480 const CanonicalStructType* struct_type =
481 GetTypeCanonicalizer()->LookupStruct(canonical_index);
482 auto const& entry = fieldnames.try_emplace(
483 struct_index, size_t{struct_type->field_count()});
484 std::vector<base::OwnedVector<char>>& field_names = entry.first->second;
485 uint32_t fields_count = decoder.consume_u32v("fields count");
486 for (uint32_t j = 0; j < fields_count; j++) {
487 uint32_t field_index = decoder.consume_u32v("field index");
489 &decoder, unibrow::Utf8Variant::kLossyUtf8, "field name");
490 if (!decoder.ok()) break;
491 if (field_index >= field_names.size()) continue;
492 if (!field_names[field_index].empty()) continue;
493 if (!validate_utf8(&decoder, name)) continue;
494 uint32_t length = name.length();
495 field_names[field_index] = base::OwnedVector<char>::NewByCopying(
496 base + name.offset(), length);
497 *total_allocated_size += length;
498 }
499 if (!decoder.ok()) break;
500 }
501 } else {
502 // We don't care about this subsection here.
503 decoder.consume_bytes(name_payload_len, "name subsection payload");
504 }
505 }
506}
507
508namespace {
509// A task that validates multiple functions in parallel, storing the earliest
510// validation error in {this} decoder.
511class ValidateFunctionsTask : public JobTask {
512 public:
513 explicit ValidateFunctionsTask(
514 base::Vector<const uint8_t> wire_bytes, const WasmModule* module,
515 WasmEnabledFeatures enabled_features, std::function<bool(int)> filter,
516 WasmError* error_out,
517 std::atomic<WasmDetectedFeatures>* detected_features)
518 : wire_bytes_(wire_bytes),
519 module_(module),
520 enabled_features_(enabled_features),
521 filter_(std::move(filter)),
522 next_function_(module->num_imported_functions),
523 after_last_function_(next_function_ + module->num_declared_functions),
524 error_out_(error_out),
525 detected_features_(detected_features) {
526 DCHECK(!error_out->has_error());
527 }
528
529 void Run(JobDelegate* delegate) override {
530 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
531 "wasm.ValidateFunctionsTask");
532
533 WasmDetectedFeatures detected_features;
534 Zone zone(GetWasmEngine()->allocator(), ZONE_NAME);
535 do {
536 // Get the index of the next function to validate.
537 // {fetch_add} might overrun {after_last_function_} by a bit. Since the
538 // number of functions is limited to a value much smaller than the
539 // integer range, this is near impossible to happen.
540 static_assert(kV8MaxWasmTotalFunctions < kMaxInt / 2);
541 int func_index;
542 do {
543 func_index = next_function_.fetch_add(1, std::memory_order_relaxed);
544 if (V8_UNLIKELY(func_index >= after_last_function_)) {
545 UpdateDetectedFeatures(detected_features);
546 return;
547 }
548 DCHECK_LE(0, func_index);
549 } while ((filter_ && !filter_(func_index)) ||
550 module_->function_was_validated(func_index));
551
552 zone.Reset();
553 if (!ValidateFunction(func_index, &zone, &detected_features)) {
554 // No need to validate any more functions.
555 next_function_.store(after_last_function_, std::memory_order_relaxed);
556 return;
557 }
558 } while (!delegate->ShouldYield());
559 UpdateDetectedFeatures(detected_features);
560 }
561
562 size_t GetMaxConcurrency(size_t /* worker_count */) const override {
563 int next_func = next_function_.load(std::memory_order_relaxed);
564 return std::max(0, after_last_function_ - next_func);
565 }
566
567 private:
568 bool ValidateFunction(int func_index, Zone* zone,
569 WasmDetectedFeatures* detected_features) {
570 const WasmFunction& function = module_->functions[func_index];
571 DCHECK_LT(0, function.code.offset());
572 bool is_shared = module_->type(function.sig_index).is_shared;
573 FunctionBody body{function.sig, function.code.offset(),
574 wire_bytes_.begin() + function.code.offset(),
575 wire_bytes_.begin() + function.code.end_offset(),
576 is_shared};
577 DecodeResult validation_result = ValidateFunctionBody(
578 zone, enabled_features_, module_, detected_features, body);
579 if (V8_UNLIKELY(validation_result.failed())) {
580 SetError(func_index, std::move(validation_result).error());
581 return false;
582 }
583 module_->set_function_validated(func_index);
584 return true;
585 }
586
587 // Set the error from the argument if it's earlier than the error we already
588 // have (or if we have none yet). Thread-safe.
589 void SetError(int func_index, WasmError error) {
591 if (error_out_->has_error() && error_out_->offset() <= error.offset()) {
592 return;
593 }
594 *error_out_ = GetWasmErrorWithName(wire_bytes_, func_index, module_, error);
595 }
596
597 void UpdateDetectedFeatures(WasmDetectedFeatures detected_features) {
598 WasmDetectedFeatures old_features =
599 detected_features_->load(std::memory_order_relaxed);
600 while (!detected_features_->compare_exchange_weak(
601 old_features, old_features | detected_features,
602 std::memory_order_relaxed)) {
603 // Retry with updated {old_features}.
604 }
605 }
606
607 const base::Vector<const uint8_t> wire_bytes_;
608 const WasmModule* const module_;
609 const WasmEnabledFeatures enabled_features_;
610 const std::function<bool(int)> filter_;
611 std::atomic<int> next_function_;
613 base::Mutex set_error_mutex_;
614 WasmError* const error_out_;
615 std::atomic<WasmDetectedFeatures>* const detected_features_;
616};
617} // namespace
618
620 WasmEnabledFeatures enabled_features,
622 std::function<bool(int)> filter,
623 WasmDetectedFeatures* detected_features_out) {
624 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
625 "wasm.ValidateFunctions", "num_declared_functions",
626 module->num_declared_functions, "has_filter", filter != nullptr);
627 DCHECK_EQ(kWasmOrigin, module->origin);
628
629 class NeverYieldDelegate final : public JobDelegate {
630 public:
631 bool ShouldYield() override { return false; }
632
633 bool IsJoiningThread() const override { UNIMPLEMENTED(); }
634 void NotifyConcurrencyIncrease() override { UNIMPLEMENTED(); }
635 uint8_t GetTaskId() override { UNIMPLEMENTED(); }
636 };
637
638 // Create a {ValidateFunctionsTask} to validate all functions. The earliest
639 // error found will be set on this decoder.
640 WasmError validation_error;
641 std::atomic<WasmDetectedFeatures> detected_features;
642 std::unique_ptr<JobTask> validate_job =
643 std::make_unique<ValidateFunctionsTask>(
644 wire_bytes, module, enabled_features, std::move(filter),
645 &validation_error, &detected_features);
646
647 if (v8_flags.single_threaded) {
648 // In single-threaded mode, run the {ValidateFunctionsTask} synchronously.
649 NeverYieldDelegate delegate;
650 validate_job->Run(&delegate);
651 } else {
652 // Spawn the task and join it.
653 std::unique_ptr<JobHandle> job_handle = V8::GetCurrentPlatform()->CreateJob(
654 TaskPriority::kUserVisible, std::move(validate_job));
655 job_handle->Join();
656 }
657
658 *detected_features_out |= detected_features.load(std::memory_order_relaxed);
659 return validation_error;
660}
661
663 int func_index, const WasmModule* module,
664 WasmError error) {
665 WasmName name = ModuleWireBytes{wire_bytes}.GetNameOrNull(func_index, module);
666 if (name.begin() == nullptr) {
667 return WasmError(error.offset(), "Compiling function #%d failed: %s",
668 func_index, error.message().c_str());
669 } else {
670 TruncatedUserString<> truncated_name(name);
671 return WasmError(error.offset(),
672 "Compiling function #%d:\"%.*s\" failed: %s", func_index,
673 truncated_name.length(), truncated_name.start(),
674 error.message().c_str());
675 }
676}
677
679 WireBytesRef name_section) {
680 if (name_section.is_empty()) return; // No name section.
681 Decoder decoder(wire_bytes.begin() + name_section.offset(),
682 wire_bytes.begin() + name_section.end_offset(),
683 name_section.offset());
684 while (decoder.ok() && decoder.more()) {
685 uint8_t name_type = decoder.consume_u8("name type");
686 if (name_type & 0x80) break; // no varuint7
687
688 uint32_t name_payload_len = decoder.consume_u32v("name payload length");
689 if (!decoder.checkAvailable(name_payload_len)) break;
690
691 switch (name_type) {
692 case kModuleCode:
693 case kFunctionCode:
694 // Already handled elsewhere.
695 decoder.consume_bytes(name_payload_len);
696 break;
697 case kLocalCode:
700 DecodeIndirectNameMap(local_names_, decoder, name_payload_len);
701 break;
702 case kLabelCode:
705 DecodeIndirectNameMap(label_names_, decoder, name_payload_len);
706 break;
707 case kTypeCode:
708 static_assert(kV8MaxWasmTypes <= NameMap::kMaxKey);
709 DecodeNameMap(type_names_, decoder, name_payload_len);
710 break;
711 case kTableCode:
712 static_assert(kV8MaxWasmTables <= NameMap::kMaxKey);
713 DecodeNameMap(table_names_, decoder, name_payload_len);
714 break;
715 case kMemoryCode:
716 static_assert(kV8MaxWasmMemories <= NameMap::kMaxKey);
717 DecodeNameMap(memory_names_, decoder, name_payload_len);
718 break;
719 case kGlobalCode:
720 static_assert(kV8MaxWasmGlobals <= NameMap::kMaxKey);
721 DecodeNameMap(global_names_, decoder, name_payload_len);
722 break;
725 DecodeNameMap(element_segment_names_, decoder, name_payload_len);
726 break;
727 case kDataSegmentCode:
729 DecodeNameMap(data_segment_names_, decoder, name_payload_len);
730 break;
731 case kFieldCode:
734 DecodeIndirectNameMap(field_names_, decoder, name_payload_len);
735 break;
736 case kTagCode:
737 static_assert(kV8MaxWasmTags <= NameMap::kMaxKey);
738 DecodeNameMap(tag_names_, decoder, name_payload_len);
739 break;
740 }
741 }
742}
743
744#undef TRACE
745
746} // namespace wasm
747} // namespace internal
748} // namespace v8
friend Zone
Definition asm-types.cc:195
virtual bool ShouldYield()=0
std::unique_ptr< JobHandle > CreateJob(TaskPriority priority, std::unique_ptr< JobTask > job_task, const SourceLocation &location=SourceLocation::Current())
static OwnedVector< U > NewByCopying(const U *data, size_t size)
Definition vector.h:303
constexpr size_t size() const
Definition vector.h:70
constexpr T * begin() const
Definition vector.h:96
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
DecodedNameSection(base::Vector< const uint8_t > wire_bytes, WireBytesRef name_section)
Result< R > toResult(T &&val)
Definition decoder.h:378
int32_t consume_i32v(const char *name="var_int32")
Definition decoder.h:269
const uint8_t * pc() const
Definition decoder.h:408
bool checkAvailable(uint32_t size)
Definition decoder.h:321
void consume_bytes(uint32_t size, const char *name="skip")
Definition decoder.h:297
uint32_t consume_u32v(const char *name="var_uint32")
Definition decoder.h:251
uint32_t V8_INLINE pc_offset(const uint8_t *pc) const
Definition decoder.h:413
uint8_t consume_u8(const char *name="uint8_t")
Definition decoder.h:225
void V8_NOINLINE V8_PRESERVE_MOST error(const char *msg)
Definition decoder.h:331
static constexpr ITracer * NoTrace
Definition decoder.h:45
ConstantExpression DecodeInitExprForTesting(ValueType expected)
ModuleResult DecodeModule(bool validate_functions)
FunctionResult DecodeSingleFunctionForTesting(Zone *zone, ModuleWireBytes wire_bytes, const WasmModule *module)
void DecodeSection(SectionCode section_code, base::Vector< const uint8_t > bytes, uint32_t offset)
void StartCodeSection(WireBytesRef section_bytes)
const std::shared_ptr< WasmModule > & shared_module() const
ModuleDecoder(WasmEnabledFeatures enabled_features, WasmDetectedFeatures *detected_features)
void DecodeModuleHeader(base::Vector< const uint8_t > bytes)
static size_t IdentifyUnknownSection(ModuleDecoder *decoder, base::Vector< const uint8_t > bytes, uint32_t offset, SectionCode *result)
std::unique_ptr< ModuleDecoderImpl > impl_
void DecodeFunctionBody(uint32_t index, uint32_t size, uint32_t offset)
bool CheckFunctionsCount(uint32_t functions_count, uint32_t error_offset)
V8_EXPORT_PRIVATE const CanonicalStructType * LookupStruct(CanonicalTypeIndex index) const
static constexpr WasmEnabledFeatures All()
uint32_t count
std::ostream & impl_
int32_t offset
ZoneVector< RpoNumber > & result
std::atomic< WasmDetectedFeatures > detected_features_
const base::Vector< const uint8_t > wire_bytes_
const WasmEnabledFeatures enabled_features_
WasmError *const error_out_
const int after_last_function_
const std::function< bool(int)> filter_
std::atomic< int > next_function_
base::Mutex set_error_mutex_
STL namespace.
LockGuard< Mutex > MutexGuard
Definition mutex.h:219
constexpr size_t kV8MaxWasmTableInitEntries
Definition wasm-limits.h:59
constexpr char kNameString[]
constexpr char kInstTraceString[]
const char * SectionName(SectionCode code)
void DecodeFunctionNames(base::Vector< const uint8_t > wire_bytes, NameMap &names)
VoidResult DecodeResult
Definition decoder.h:39
void DecodeCanonicalTypeNames(base::Vector< const uint8_t > wire_bytes, const WasmModule *module, std::vector< base::OwnedVector< char > > &typenames, std::map< uint32_t, std::vector< base::OwnedVector< char > > > &fieldnames, size_t *total_allocated_size)
constexpr size_t kV8MaxWasmFunctionLocals
Definition wasm-limits.h:52
SectionCode IdentifyUnknownSectionInternal(Decoder *decoder, ITracer *tracer)
constexpr size_t kV8MaxWasmFunctionSize
Definition wasm-limits.h:51
ModuleResult DecodeWasmModuleForDisassembler(base::Vector< const uint8_t > wire_bytes, ITracer *tracer)
TypeCanonicalizer * GetTypeCanonicalizer()
constexpr size_t kV8MaxWasmModuleSize
Definition wasm-limits.h:50
AsmJsOffsetsResult DecodeAsmJsOffsets(base::Vector< const uint8_t > encoded_offsets)
AdaptiveMap< WireBytesRef > NameMap
ModuleResult DecodeWasmModule(WasmEnabledFeatures enabled_features, base::Vector< const uint8_t > wire_bytes, bool validate_functions, ModuleOrigin origin, Counters *counters, std::shared_ptr< metrics::Recorder > metrics_recorder, v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method, WasmDetectedFeatures *detected_features)
constexpr char kSourceMappingURLString[]
constexpr size_t kV8MaxWasmTypes
Definition wasm-limits.h:30
constexpr char kBuildIdString[]
bool validate_utf8(Decoder *decoder, WireBytesRef string)
Result< const FunctionSig * > DecodeWasmSignatureForTesting(WasmEnabledFeatures enabled_features, Zone *zone, base::Vector< const uint8_t > bytes)
constexpr size_t kV8MaxWasmTables
Definition wasm-limits.h:60
WasmError ValidateFunctions(const WasmModule *module, WasmEnabledFeatures enabled_features, base::Vector< const uint8_t > wire_bytes, std::function< bool(int)> filter, WasmDetectedFeatures *detected_features_out)
DecodeResult ValidateFunctionBody(Zone *zone, WasmEnabledFeatures enabled, const WasmModule *module, WasmDetectedFeatures *detected, const FunctionBody &body)
constexpr size_t kV8MaxWasmMemories
Definition wasm-limits.h:61
constexpr char kCompilationHintsString[]
constexpr char kExternalDebugInfoString[]
WasmEngine * GetWasmEngine()
constexpr size_t kV8MaxWasmDataSegments
Definition wasm-limits.h:37
AdaptiveMap< AdaptiveMap< WireBytesRef > > IndirectNameMap
std::vector< CustomSectionOffset > DecodeCustomSections(base::Vector< const uint8_t > bytes)
constexpr size_t kV8MaxWasmTotalFunctions
Definition wasm-limits.h:88
constexpr size_t kV8MaxWasmGlobals
Definition wasm-limits.h:34
ConstantExpression DecodeWasmInitExprForTesting(WasmEnabledFeatures enabled_features, base::Vector< const uint8_t > bytes, ValueType expected)
WireBytesRef consume_string(Decoder *decoder, unibrow::Utf8Variant grammar, const char *name, ITracer *tracer)
FunctionResult DecodeWasmFunctionForTesting(WasmEnabledFeatures enabled_features, Zone *zone, ModuleWireBytes wire_bytes, const WasmModule *module, base::Vector< const uint8_t > function_bytes)
constexpr char kBranchHintsString[]
constexpr size_t kV8MaxWasmStructFields
Definition wasm-limits.h:64
WasmError GetWasmErrorWithName(base::Vector< const uint8_t > wire_bytes, int func_index, const WasmModule *module, WasmError error)
constexpr size_t kV8MaxWasmTags
Definition wasm-limits.h:35
constexpr char kDebugInfoString[]
wasm::WasmModule WasmModule
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr int kMaxInt
Definition globals.h:374
JSArrayBuffer::IsDetachableBit is_shared
wasm::WasmFunction WasmFunction
Definition c-api.cc:87
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define UNIMPLEMENTED()
Definition logging.h:66
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
WasmName GetNameOrNull(WireBytesRef ref) const
bool has_struct(ModuleTypeIndex index) const
bool has_type(ModuleTypeIndex index) const
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_DISABLED_BY_DEFAULT(name)
#define V8_UNLIKELY(condition)
Definition v8config.h:660
const wasm::WasmModule * module_
#define SELECT_WASM_COUNTER(counters, origin, prefix, suffix)
#define ZONE_NAME
Definition zone.h:22