module-decoder.cc 17.4 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

jfb's avatar
jfb committed
5 6
#include "src/wasm/module-decoder.h"

7
#include "src/logging/metrics.h"
8
#include "src/wasm/constant-expression.h"
9
#include "src/wasm/decoder.h"
10
#include "src/wasm/module-decoder-impl.h"
11 12
#include "src/wasm/struct-types.h"
#include "src/wasm/wasm-constants.h"
13
#include "src/wasm/wasm-engine.h"
14
#include "src/wasm/wasm-limits.h"
15
#include "src/wasm/wasm-opcodes-inl.h"
16 17 18 19 20

namespace v8 {
namespace internal {
namespace wasm {

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
const char* SectionName(SectionCode code) {
  switch (code) {
    case kUnknownSectionCode:
      return "Unknown";
    case kTypeSectionCode:
      return "Type";
    case kImportSectionCode:
      return "Import";
    case kFunctionSectionCode:
      return "Function";
    case kTableSectionCode:
      return "Table";
    case kMemorySectionCode:
      return "Memory";
    case kGlobalSectionCode:
      return "Global";
    case kExportSectionCode:
      return "Export";
    case kStartSectionCode:
      return "Start";
    case kCodeSectionCode:
      return "Code";
    case kElementSectionCode:
      return "Element";
    case kDataSectionCode:
      return "Data";
    case kTagSectionCode:
      return "Tag";
    case kStringRefSectionCode:
      return "StringRef";
    case kDataCountSectionCode:
      return "DataCount";
    case kNameSectionCode:
      return kNameString;
    case kSourceMappingURLSectionCode:
      return kSourceMappingURLString;
    case kDebugInfoSectionCode:
      return kDebugInfoString;
    case kExternalDebugInfoSectionCode:
      return kExternalDebugInfoString;
    case kCompilationHintsSectionCode:
      return kCompilationHintsString;
    case kBranchHintsSectionCode:
      return kBranchHintsString;
    default:
      return "<unknown>";
  }
}

70 71 72 73 74 75
ModuleResult DecodeWasmModule(
    const WasmFeatures& enabled, const byte* module_start,
    const byte* module_end, bool verify_functions, ModuleOrigin origin,
    Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder,
    v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method,
    AccountingAllocator* allocator) {
76
  size_t size = module_end - module_start;
77
  CHECK_LE(module_start, module_end);
78 79 80 81
  size_t max_size = max_module_size();
  if (size > max_size) {
    return ModuleResult{
        WasmError{0, "size > maximum module size (%zu): %zu", max_size, size}};
82
  }
83
  // TODO(bradnelson): Improve histogram handling of size_t.
84 85
  auto size_counter =
      SELECT_WASM_COUNTER(counters, origin, wasm, module_size_bytes);
86
  size_counter->AddSample(static_cast<int>(size));
87 88
  // Signatures are stored in zone memory, which have the same lifetime
  // as the {module}.
89
  ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
90
  v8::metrics::WasmModuleDecoded metrics_event;
91 92
  base::ElapsedTimer timer;
  timer.Start();
93 94 95
  base::ThreadTicks thread_ticks = base::ThreadTicks::IsSupported()
                                       ? base::ThreadTicks::Now()
                                       : base::ThreadTicks();
96 97 98 99
  ModuleResult result =
      decoder.DecodeModule(counters, allocator, verify_functions);

  // Record event metrics.
100 101
  metrics_event.wall_clock_duration_in_us = timer.Elapsed().InMicroseconds();
  timer.Stop();
102 103 104 105
  if (!thread_ticks.IsNull()) {
    metrics_event.cpu_duration_in_us =
        (base::ThreadTicks::Now() - thread_ticks).InMicroseconds();
  }
106 107 108 109 110 111 112 113 114 115 116 117 118 119
  metrics_event.success = decoder.ok() && result.ok();
  metrics_event.async = decoding_method == DecodingMethod::kAsync ||
                        decoding_method == DecodingMethod::kAsyncStream;
  metrics_event.streamed = decoding_method == DecodingMethod::kSyncStream ||
                           decoding_method == DecodingMethod::kAsyncStream;
  if (result.ok()) {
    metrics_event.function_count = result.value()->num_declared_functions;
  } else if (auto&& module = decoder.shared_module()) {
    metrics_event.function_count = module->num_declared_functions;
  }
  metrics_event.module_size_in_bytes = size;
  metrics_recorder->DelayMainThreadEvent(metrics_event, context_id);

  return result;
120 121
}

122 123 124 125 126 127 128 129 130
ModuleResult DecodeWasmModuleForDisassembler(const byte* module_start,
                                             const byte* module_end,
                                             AccountingAllocator* allocator) {
  constexpr bool verify_functions = false;
  ModuleDecoderImpl decoder(WasmFeatures::All(), module_start, module_end,
                            kWasmOrigin);
  return decoder.DecodeModule(nullptr, allocator, verify_functions);
}

131 132 133
ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled)
    : enabled_features_(enabled) {}

134 135
ModuleDecoder::~ModuleDecoder() = default;

136 137 138
const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
  return impl_->shared_module();
}
139

140 141 142 143
void ModuleDecoder::StartDecoding(
    Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder,
    v8::metrics::Recorder::ContextId context_id, AccountingAllocator* allocator,
    ModuleOrigin origin) {
144
  DCHECK_NULL(impl_);
145
  impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
146
  impl_->StartDecoding(counters, allocator);
147 148
}

149
void ModuleDecoder::DecodeModuleHeader(base::Vector<const uint8_t> bytes,
150 151 152 153 154
                                       uint32_t offset) {
  impl_->DecodeModuleHeader(bytes, offset);
}

void ModuleDecoder::DecodeSection(SectionCode section_code,
155 156
                                  base::Vector<const uint8_t> bytes,
                                  uint32_t offset, bool verify_functions) {
157 158 159 160 161 162 163 164
  impl_->DecodeSection(section_code, bytes, offset, verify_functions);
}

void ModuleDecoder::DecodeFunctionBody(uint32_t index, uint32_t length,
                                       uint32_t offset, bool verify_functions) {
  impl_->DecodeFunctionBody(index, length, offset, verify_functions);
}

165 166 167
void ModuleDecoder::StartCodeSection(WireBytesRef section_bytes) {
  impl_->StartCodeSection(section_bytes);
}
168

169
bool ModuleDecoder::CheckFunctionsCount(uint32_t functions_count,
170 171
                                        uint32_t error_offset) {
  return impl_->CheckFunctionsCount(functions_count, error_offset);
172 173 174 175 176 177
}

ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) {
  return impl_->FinishDecoding(verify_functions);
}

178
size_t ModuleDecoder::IdentifyUnknownSection(ModuleDecoder* decoder,
179
                                             base::Vector<const uint8_t> bytes,
180 181 182 183 184 185
                                             uint32_t offset,
                                             SectionCode* result) {
  if (!decoder->ok()) return 0;
  decoder->impl_->Reset(bytes, offset);
  *result = IdentifyUnknownSectionInternal(decoder->impl_.get());
  return decoder->impl_->pc() - bytes.begin();
186 187
}

188
bool ModuleDecoder::ok() { return impl_->ok(); }
189

190 191 192
const FunctionSig* DecodeWasmSignatureForTesting(const WasmFeatures& enabled,
                                                 Zone* zone, const byte* start,
                                                 const byte* end) {
193
  ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
194
  return decoder.DecodeFunctionSignature(zone, start);
195 196
}

197 198 199 200
ConstantExpression DecodeWasmInitExprForTesting(const WasmFeatures& enabled,
                                                const byte* start,
                                                const byte* end,
                                                ValueType expected) {
201
  ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
202 203 204
  AccountingAllocator allocator;
  decoder.StartDecoding(nullptr, &allocator);
  return decoder.DecodeInitExprForTesting(expected);
205 206
}

207
FunctionResult DecodeWasmFunctionForTesting(
208 209 210
    const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
    const WasmModule* module, const byte* function_start,
    const byte* function_end, Counters* counters) {
211
  size_t size = function_end - function_start;
212 213
  CHECK_LE(function_start, function_end);
  if (size > kV8MaxWasmFunctionSize) {
214 215 216
    return FunctionResult{WasmError{0,
                                    "size > maximum function size (%zu): %zu",
                                    kV8MaxWasmFunctionSize, size}};
217
  }
218
  ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin);
219
  decoder.SetCounters(counters);
220
  return decoder.DecodeSingleFunction(zone, wire_bytes, module);
221
}
222

223 224
AsmJsOffsetsResult DecodeAsmJsOffsets(
    base::Vector<const uint8_t> encoded_offsets) {
225
  std::vector<AsmJsOffsetFunctionEntries> functions;
226

227
  Decoder decoder(encoded_offsets);
228
  uint32_t functions_count = decoder.consume_u32v("functions count");
229
  // Consistency check.
230 231
  DCHECK_GE(encoded_offsets.size(), functions_count);
  functions.reserve(functions_count);
232

233
  for (uint32_t i = 0; i < functions_count; ++i) {
234 235
    uint32_t size = decoder.consume_u32v("table size");
    if (size == 0) {
236
      functions.emplace_back();
237 238
      continue;
    }
239
    DCHECK(decoder.checkAvailable(size));
240
    const byte* table_end = decoder.pc() + size;
241 242
    uint32_t locals_size = decoder.consume_u32v("locals size");
    int function_start_position = decoder.consume_u32v("function start pos");
243
    int function_end_position = function_start_position;
244
    int last_byte_offset = locals_size;
245
    int last_asm_position = function_start_position;
246
    std::vector<AsmJsOffsetEntry> func_asm_offsets;
247
    func_asm_offsets.reserve(size / 4);  // conservative estimation
248 249 250
    // Add an entry for the stack check, associated with position 0.
    func_asm_offsets.push_back(
        {0, function_start_position, function_start_position});
251 252
    while (decoder.pc() < table_end) {
      DCHECK(decoder.ok());
253
      last_byte_offset += decoder.consume_u32v("byte offset delta");
254 255 256 257 258
      int call_position =
          last_asm_position + decoder.consume_i32v("call position delta");
      int to_number_position =
          call_position + decoder.consume_i32v("to_number position delta");
      last_asm_position = to_number_position;
259 260 261 262 263 264 265 266
      if (decoder.pc() == table_end) {
        // The last entry is the function end marker.
        DCHECK_EQ(call_position, to_number_position);
        function_end_position = call_position;
      } else {
        func_asm_offsets.push_back(
            {last_byte_offset, call_position, to_number_position});
      }
267
    }
268
    DCHECK_EQ(decoder.pc(), table_end);
269 270 271
    functions.emplace_back(AsmJsOffsetFunctionEntries{
        function_start_position, function_end_position,
        std::move(func_asm_offsets)});
272
  }
273 274
  DCHECK(decoder.ok());
  DCHECK(!decoder.more());
275

276
  return decoder.toResult(AsmJsOffsets{std::move(functions)});
277 278
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
                                                      const byte* end) {
  Decoder decoder(start, end);
  decoder.consume_bytes(4, "wasm magic");
  decoder.consume_bytes(4, "wasm version");

  std::vector<CustomSectionOffset> result;

  while (decoder.more()) {
    byte section_code = decoder.consume_u8("section code");
    uint32_t section_length = decoder.consume_u32v("section length");
    uint32_t section_start = decoder.pc_offset();
    if (section_code != 0) {
      // Skip known sections.
      decoder.consume_bytes(section_length, "section bytes");
      continue;
    }
    uint32_t name_length = decoder.consume_u32v("name length");
    uint32_t name_offset = decoder.pc_offset();
    decoder.consume_bytes(name_length, "section name");
    uint32_t payload_offset = decoder.pc_offset();
300 301 302 303
    if (section_length < (payload_offset - section_start)) {
      decoder.error("invalid section length");
      break;
    }
304 305
    uint32_t payload_length = section_length - (payload_offset - section_start);
    decoder.consume_bytes(payload_length);
306
    if (decoder.failed()) break;
307 308 309
    result.push_back({{section_start, section_length},
                      {name_offset, name_length},
                      {payload_offset, payload_length}});
310 311 312 313 314
  }

  return result;
}

315
namespace {
316

317
bool FindNameSection(Decoder* decoder) {
318
  static constexpr int kModuleHeaderSize = 8;
319
  decoder->consume_bytes(kModuleHeaderSize, "module header");
320 321 322

  WasmSectionIterator section_iter(decoder);

323
  while (decoder->ok() && section_iter.more() &&
324 325 326
         section_iter.section_code() != kNameSectionCode) {
    section_iter.advance(true);
  }
327
  if (!section_iter.more()) return false;
328 329

  // Reset the decoder to not read beyond the name section end.
330
  decoder->Reset(section_iter.payload(), decoder->pc_offset());
331 332 333
  return true;
}

334
enum EmptyNames : bool { kAllowEmptyNames, kSkipEmptyNames };
335

336 337
void DecodeNameMap(NameMap& target, Decoder& decoder,
                   EmptyNames empty_names = kSkipEmptyNames) {
338 339 340 341
  uint32_t count = decoder.consume_u32v("names count");
  for (uint32_t i = 0; i < count; i++) {
    uint32_t index = decoder.consume_u32v("index");
    WireBytesRef name =
342
        consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, "name");
343
    if (!decoder.ok()) break;
344 345
    if (index > NameMap::kMaxKey) continue;
    if (empty_names == kSkipEmptyNames && name.is_empty()) continue;
346
    if (!validate_utf8(&decoder, name)) continue;
347
    target.Put(index, name);
348
  }
349
  target.FinishInitialization();
350
}
351

352 353 354 355
void DecodeIndirectNameMap(IndirectNameMap& target, Decoder& decoder) {
  uint32_t outer_count = decoder.consume_u32v("outer count");
  for (uint32_t i = 0; i < outer_count; ++i) {
    uint32_t outer_index = decoder.consume_u32v("outer index");
356
    if (outer_index > IndirectNameMap::kMaxKey) continue;
357
    NameMap names;
358 359 360
    uint32_t inner_count = decoder.consume_u32v("inner count");
    for (uint32_t k = 0; k < inner_count; ++k) {
      uint32_t inner_index = decoder.consume_u32v("inner index");
361
      WireBytesRef name =
362
          consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, "name");
363
      if (!decoder.ok()) break;
364
      if (inner_index > NameMap::kMaxKey) continue;
365
      if (name.is_empty()) continue;  // Empty names are useless.
366
      if (!validate_utf8(&decoder, name)) continue;
367
      names.Put(inner_index, name);
368
    }
369 370
    names.FinishInitialization();
    target.Put(outer_index, std::move(names));
371
  }
372
  target.FinishInitialization();
373 374
}

375
}  // namespace
376

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
void DecodeFunctionNames(const byte* module_start, const byte* module_end,
                         NameMap& names) {
  Decoder decoder(module_start, module_end);
  if (FindNameSection(&decoder)) {
    while (decoder.ok() && decoder.more()) {
      uint8_t name_type = decoder.consume_u8("name type");
      if (name_type & 0x80) break;  // no varuint7

      uint32_t name_payload_len = decoder.consume_u32v("name payload length");
      if (!decoder.checkAvailable(name_payload_len)) break;

      if (name_type != NameSectionKindCode::kFunctionCode) {
        decoder.consume_bytes(name_payload_len, "name subsection payload");
        continue;
      }
      // We need to allow empty function names for spec-conformant stack traces.
      DecodeNameMap(names, decoder, kAllowEmptyNames);
    }
  }
}

398 399 400 401 402 403
DecodedNameSection::DecodedNameSection(base::Vector<const uint8_t> wire_bytes,
                                       WireBytesRef name_section) {
  if (name_section.is_empty()) return;  // No name section.
  Decoder decoder(wire_bytes.begin() + name_section.offset(),
                  wire_bytes.begin() + name_section.end_offset(),
                  name_section.offset());
404 405 406 407 408 409 410
  while (decoder.ok() && decoder.more()) {
    uint8_t name_type = decoder.consume_u8("name type");
    if (name_type & 0x80) break;  // no varuint7

    uint32_t name_payload_len = decoder.consume_u32v("name payload length");
    if (!decoder.checkAvailable(name_payload_len)) break;

411 412 413 414 415 416 417
    switch (name_type) {
      case kModuleCode:
      case kFunctionCode:
        // Already handled elsewhere.
        decoder.consume_bytes(name_payload_len);
        break;
      case kLocalCode:
418 419
        static_assert(kV8MaxWasmFunctions <= IndirectNameMap::kMaxKey);
        static_assert(kV8MaxWasmFunctionLocals <= NameMap::kMaxKey);
420 421 422
        DecodeIndirectNameMap(local_names_, decoder);
        break;
      case kLabelCode:
423 424
        static_assert(kV8MaxWasmFunctions <= IndirectNameMap::kMaxKey);
        static_assert(kV8MaxWasmFunctionSize <= NameMap::kMaxKey);
425 426 427
        DecodeIndirectNameMap(label_names_, decoder);
        break;
      case kTypeCode:
428
        static_assert(kV8MaxWasmTypes <= NameMap::kMaxKey);
429 430 431
        DecodeNameMap(type_names_, decoder);
        break;
      case kTableCode:
432
        static_assert(kV8MaxWasmTables <= NameMap::kMaxKey);
433 434 435
        DecodeNameMap(table_names_, decoder);
        break;
      case kMemoryCode:
436
        static_assert(kV8MaxWasmMemories <= NameMap::kMaxKey);
437 438 439
        DecodeNameMap(memory_names_, decoder);
        break;
      case kGlobalCode:
440
        static_assert(kV8MaxWasmGlobals <= NameMap::kMaxKey);
441 442 443
        DecodeNameMap(global_names_, decoder);
        break;
      case kElementSegmentCode:
444
        static_assert(kV8MaxWasmTableInitEntries <= NameMap::kMaxKey);
445 446 447
        DecodeNameMap(element_segment_names_, decoder);
        break;
      case kDataSegmentCode:
448
        static_assert(kV8MaxWasmDataSegments <= NameMap::kMaxKey);
449 450 451
        DecodeNameMap(data_segment_names_, decoder);
        break;
      case kFieldCode:
452 453
        static_assert(kV8MaxWasmTypes <= IndirectNameMap::kMaxKey);
        static_assert(kV8MaxWasmStructFields <= NameMap::kMaxKey);
454 455 456
        DecodeIndirectNameMap(field_names_, decoder);
        break;
      case kTagCode:
457
        static_assert(kV8MaxWasmTags <= NameMap::kMaxKey);
458 459
        DecodeNameMap(tag_names_, decoder);
        break;
460 461 462 463
    }
  }
}

464 465
#undef TRACE

466 467 468
}  // namespace wasm
}  // namespace internal
}  // namespace v8