79 std::shared_ptr<metrics::Recorder> metrics_recorder,
86 size_counter->AddSample(
static_cast<int>(wire_bytes.
size()));
95 if (counters &&
result.ok()) {
99 static_cast<int>(
result.value()->num_declared_functions));
114 metrics_recorder->DelayMainThreadEvent(metrics_event, context_id);
124 "wasm.DecodeWasmModule");
133 constexpr bool kNoValidateFunctions =
false;
136 &unused_detected_features, tracer};
144 detected_features)) {}
149 return impl_->shared_module();
153 impl_->DecodeModuleHeader(bytes);
168 impl_->StartCodeSection(section_bytes);
172 uint32_t error_offset) {
173 return impl_->CheckFunctionsCount(functions_count, error_offset);
182 if (!decoder->
ok())
return 0;
186 return decoder->
impl_->pc() - bytes.begin();
196 &unused_detected_features};
198 decoder.DecodeFunctionSignatureForTesting(zone, bytes.begin()));
206 &unused_detected_features};
216 WasmError{0,
"size > maximum function size (%zu): %zu",
221 &unused_detected_features};
227 std::vector<AsmJsOffsetFunctionEntries> functions;
229 Decoder decoder(encoded_offsets);
230 uint32_t functions_count = decoder.
consume_u32v(
"functions count");
233 functions.reserve(functions_count);
235 for (uint32_t
i = 0;
i < functions_count; ++
i) {
238 functions.emplace_back();
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);
251 func_asm_offsets.push_back(
252 {0, function_start_position, function_start_position});
253 while (decoder.
pc() < table_end) {
255 last_byte_offset += decoder.
consume_u32v(
"byte offset delta");
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) {
263 DCHECK_EQ(call_position, to_number_position);
264 function_end_position = call_position;
266 func_asm_offsets.push_back(
267 {last_byte_offset, call_position, to_number_position});
272 function_start_position, function_end_position,
273 std::move(func_asm_offsets)});
287 std::vector<CustomSectionOffset>
result;
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) {
298 uint32_t name_length = decoder.
consume_u32v(
"name length");
299 uint32_t name_offset = decoder.
pc_offset();
301 uint32_t payload_offset = decoder.
pc_offset();
302 if (section_length < (payload_offset - section_start)) {
303 decoder.
error(
"invalid section length");
306 uint32_t payload_length = section_length - (payload_offset - section_start);
308 if (decoder.
failed())
break;
309 result.push_back({{section_start, section_length},
310 {name_offset, name_length},
311 {payload_offset, payload_length}});
319bool FindNameSection(
Decoder* decoder) {
320 static constexpr int kModuleHeaderSize = 8;
321 decoder->consume_bytes(kModuleHeaderSize,
"module header");
325 while (decoder->ok() && section_iter.more() &&
327 section_iter.advance(
true);
329 if (!section_iter.more())
return false;
332 decoder->Reset(section_iter.payload(), decoder->pc_offset());
336enum class EmptyNames :
bool {
kAllow, kSkip };
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");
345 if (!decoder.ok())
break;
347 if (empty_names == EmptyNames::kSkip && name.is_empty())
continue;
349 target.Put(index, name);
351 target.FinishInitialization();
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);
361 DecodeNameMapInternal(target, decoder, empty_names);
365 uint32_t subsection_payload_length) {
366 if (target.is_set()) {
367 decoder.consume_bytes(subsection_payload_length);
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");
376 DecodeNameMapInternal(names, decoder);
377 target.Put(outer_index, std::move(names));
378 if (!decoder.ok())
break;
380 target.FinishInitialization();
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;
393 uint32_t name_payload_len = decoder.
consume_u32v(
"name payload length");
397 decoder.
consume_bytes(name_payload_len,
"name subsection payload");
401 DecodeNameMapInternal(names, decoder, EmptyNames::kAllow);
423 size_t* total_allocated_size) {
424 bool types_done =
false;
425 bool fields_done =
false;
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;
432 uint32_t name_payload_len = decoder.
consume_u32v(
"name payload length");
436 decoder.
consume_bytes(name_payload_len,
"name subsection payload");
441 for (uint32_t
i = 0;
i <
count;
i++) {
445 if (!decoder.
ok())
break;
446 if (!module->
has_type(module_index))
continue;
447 if (name.is_empty())
continue;
449 module->canonical_type_id(module_index);
450 uint32_t index = canonical_index.
index;
457 if (!typenames[index].empty())
continue;
459 uint32_t length = name.length();
462 *total_allocated_size +=
length;
466 decoder.
consume_bytes(name_payload_len,
"name subsection payload");
470 uint32_t types_count = decoder.
consume_u32v(
"types count");
471 for (uint32_t
i = 0;
i < types_count; ++
i) {
474 if (!module->
has_struct(module_index))
return;
476 module->canonical_type_id(module_index);
477 uint32_t struct_index = canonical_index.
index;
478 if (struct_index >= typenames.size())
return;
482 auto const& entry = fieldnames.try_emplace(
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");
490 if (!decoder.
ok())
break;
491 if (field_index >= field_names.size())
continue;
492 if (!field_names[field_index].empty())
continue;
494 uint32_t length = name.length();
497 *total_allocated_size +=
length;
499 if (!decoder.
ok())
break;
503 decoder.
consume_bytes(name_payload_len,
"name subsection payload");
511class ValidateFunctionsTask :
public JobTask {
513 explicit ValidateFunctionsTask(
515 WasmEnabledFeatures enabled_features, std::function<
bool(
int)> filter,
516 WasmError* error_out,
517 std::atomic<WasmDetectedFeatures>* detected_features)
526 DCHECK(!error_out->has_error());
531 "wasm.ValidateFunctionsTask");
533 WasmDetectedFeatures detected_features;
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);
549 }
while ((filter_ && !
filter_(func_index)) ||
550 module_->function_was_validated(func_index));
553 if (!ValidateFunction(func_index, &zone, &detected_features)) {
555 next_function_.store(after_last_function_, std::memory_order_relaxed);
559 UpdateDetectedFeatures(detected_features);
562 size_t GetMaxConcurrency(
size_t )
const override {
564 return std::max(0, after_last_function_ - next_func);
568 bool ValidateFunction(
int func_index,
Zone* zone,
569 WasmDetectedFeatures* detected_features) {
573 FunctionBody body{function.sig, function.code.offset(),
578 zone, enabled_features_, module_, detected_features, body);
580 SetError(func_index, std::move(validation_result).error());
583 module_->set_function_validated(func_index);
589 void SetError(
int func_index, WasmError error) {
597 void UpdateDetectedFeatures(WasmDetectedFeatures detected_features) {
598 WasmDetectedFeatures old_features =
601 old_features, old_features | detected_features,
602 std::memory_order_relaxed)) {
622 std::function<
bool(
int)> filter,
625 "wasm.ValidateFunctions",
"num_declared_functions",
629 class NeverYieldDelegate final :
public JobDelegate {
631 bool ShouldYield()
override {
return false; }
634 void NotifyConcurrencyIncrease()
override {
UNIMPLEMENTED(); }
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);
649 NeverYieldDelegate delegate;
650 validate_job->Run(&delegate);
658 *detected_features_out |= detected_features.load(std::memory_order_relaxed);
659 return validation_error;
666 if (name.begin() ==
nullptr) {
667 return WasmError(error.offset(),
"Compiling function #%d failed: %s",
668 func_index, error.message().c_str());
672 "Compiling function #%d:\"%.*s\" failed: %s", func_index,
674 error.message().c_str());
680 if (name_section.
is_empty())
return;
684 while (decoder.
ok() && decoder.
more()) {
685 uint8_t name_type = decoder.
consume_u8(
"name type");
686 if (name_type & 0x80)
break;
688 uint32_t name_payload_len = decoder.
consume_u32v(
"name payload length");
700 DecodeIndirectNameMap(
local_names_, decoder, name_payload_len);
705 DecodeIndirectNameMap(
label_names_, decoder, name_payload_len);
709 DecodeNameMap(
type_names_, decoder, name_payload_len);
734 DecodeIndirectNameMap(
field_names_, decoder, name_payload_len);
738 DecodeNameMap(
tag_names_, decoder, name_payload_len);
virtual bool ShouldYield()=0
static OwnedVector< U > NewByCopying(const U *data, size_t size)
constexpr size_t size() const
constexpr T * begin() const
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
static constexpr uint32_t kMaxKey
NameMap element_segment_names_
IndirectNameMap label_names_
DecodedNameSection(base::Vector< const uint8_t > wire_bytes, WireBytesRef name_section)
IndirectNameMap local_names_
IndirectNameMap field_names_
NameMap data_segment_names_
Result< R > toResult(T &&val)
int32_t consume_i32v(const char *name="var_int32")
const uint8_t * pc() const
bool checkAvailable(uint32_t size)
void consume_bytes(uint32_t size, const char *name="skip")
uint32_t consume_u32v(const char *name="var_uint32")
uint32_t V8_INLINE pc_offset(const uint8_t *pc) const
uint8_t consume_u8(const char *name="uint8_t")
void V8_NOINLINE V8_PRESERVE_MOST error(const char *msg)
static constexpr ITracer * NoTrace
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
ModuleResult FinishDecoding()
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)
uint32_t field_count() const
const char * start() const
V8_EXPORT_PRIVATE const CanonicalStructType * LookupStruct(CanonicalTypeIndex index) const
static constexpr WasmEnabledFeatures All()
uint32_t end_offset() const
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_
LockGuard< Mutex > MutexGuard
constexpr size_t kV8MaxWasmTableInitEntries
constexpr char kNameString[]
constexpr char kInstTraceString[]
const char * SectionName(SectionCode code)
@ kSourceMappingURLSectionCode
@ kExternalDebugInfoSectionCode
@ kBranchHintsSectionCode
@ kCompilationHintsSectionCode
void DecodeFunctionNames(base::Vector< const uint8_t > wire_bytes, NameMap &names)
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
SectionCode IdentifyUnknownSectionInternal(Decoder *decoder, ITracer *tracer)
constexpr size_t kV8MaxWasmFunctionSize
ModuleResult DecodeWasmModuleForDisassembler(base::Vector< const uint8_t > wire_bytes, ITracer *tracer)
TypeCanonicalizer * GetTypeCanonicalizer()
constexpr size_t kV8MaxWasmModuleSize
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
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
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
constexpr char kCompilationHintsString[]
constexpr char kExternalDebugInfoString[]
WasmEngine * GetWasmEngine()
constexpr size_t kV8MaxWasmDataSegments
AdaptiveMap< AdaptiveMap< WireBytesRef > > IndirectNameMap
std::vector< CustomSectionOffset > DecodeCustomSections(base::Vector< const uint8_t > bytes)
constexpr size_t kV8MaxWasmTotalFunctions
constexpr size_t kV8MaxWasmGlobals
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
WasmError GetWasmErrorWithName(base::Vector< const uint8_t > wire_bytes, int func_index, const WasmModule *module, WasmError error)
constexpr size_t kV8MaxWasmTags
constexpr char kDebugInfoString[]
wasm::WasmModule WasmModule
V8_EXPORT_PRIVATE FlagValues v8_flags
JSArrayBuffer::IsDetachableBit is_shared
wasm::WasmFunction WasmFunction
#define DCHECK_LE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
WasmName GetNameOrNull(WireBytesRef ref) const
uint32_t num_declared_functions
const ModuleOrigin origin
bool has_struct(ModuleTypeIndex index) const
bool has_type(ModuleTypeIndex index) const
size_t module_size_in_bytes
int64_t wall_clock_duration_in_us
#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)
const wasm::WasmModule * module_
#define SELECT_WASM_COUNTER(counters, origin, prefix, suffix)