%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/wasm/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/wasm/function-body-decoder.cc |
// 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. #include "src/wasm/function-body-decoder.h" #include "src/utils/ostreams.h" #include "src/wasm/decoder.h" #include "src/wasm/function-body-decoder-impl.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-linkage.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-opcodes-inl.h" namespace v8 { namespace internal { namespace wasm { template <typename ValidationTag> bool DecodeLocalDecls(WasmFeatures enabled, BodyLocalDecls* decls, const WasmModule* module, const uint8_t* start, const uint8_t* end, Zone* zone) { if constexpr (ValidationTag::validate) DCHECK_NOT_NULL(module); WasmFeatures no_features = WasmFeatures::None(); constexpr FixedSizeSignature<ValueType, 0, 0> kNoSig; WasmDecoder<ValidationTag> decoder(zone, module, enabled, &no_features, &kNoSig, start, end); decls->encoded_size = decoder.DecodeLocals(decoder.pc()); if (ValidationTag::validate && decoder.failed()) { DCHECK_EQ(0, decls->encoded_size); return false; } DCHECK(decoder.ok()); // Copy the decoded locals types into {decls->local_types}. DCHECK_NULL(decls->local_types); decls->num_locals = decoder.num_locals_; decls->local_types = decoder.local_types_; return true; } void DecodeLocalDecls(WasmFeatures enabled, BodyLocalDecls* decls, const uint8_t* start, const uint8_t* end, Zone* zone) { constexpr WasmModule* kNoModule = nullptr; DecodeLocalDecls<Decoder::NoValidationTag>(enabled, decls, kNoModule, start, end, zone); } bool ValidateAndDecodeLocalDeclsForTesting(WasmFeatures enabled, BodyLocalDecls* decls, const WasmModule* module, const uint8_t* start, const uint8_t* end, Zone* zone) { return DecodeLocalDecls<Decoder::BooleanValidationTag>(enabled, decls, module, start, end, zone); } BytecodeIterator::BytecodeIterator(const uint8_t* start, const uint8_t* end) : Decoder(start, end) {} BytecodeIterator::BytecodeIterator(const uint8_t* start, const uint8_t* end, BodyLocalDecls* decls, Zone* zone) : Decoder(start, end) { DCHECK_NOT_NULL(decls); DCHECK_NOT_NULL(zone); DecodeLocalDecls(WasmFeatures::All(), decls, start, end, zone); pc_ += decls->encoded_size; if (pc_ > end_) pc_ = end_; } DecodeResult ValidateFunctionBody(WasmFeatures enabled, const WasmModule* module, WasmFeatures* detected, const FunctionBody& body) { // Asm.js functions should never be validated; they are valid by design. DCHECK_EQ(kWasmOrigin, module->origin); Zone zone(GetWasmEngine()->allocator(), ZONE_NAME); WasmFullDecoder<Decoder::FullValidationTag, EmptyInterface> decoder( &zone, module, enabled, detected, body); decoder.Decode(); return decoder.toResult(nullptr); } unsigned OpcodeLength(const uint8_t* pc, const uint8_t* end) { WasmFeatures unused_detected_features; Zone* no_zone = nullptr; WasmModule* no_module = nullptr; FunctionSig* no_sig = nullptr; WasmDecoder<Decoder::NoValidationTag> decoder( no_zone, no_module, WasmFeatures::All(), &unused_detected_features, no_sig, pc, end, 0); return WasmDecoder<Decoder::NoValidationTag>::OpcodeLength(&decoder, pc); } bool CheckHardwareSupportsSimd() { return CpuFeatures::SupportsWasmSimd128(); } void PrintRawWasmCode(const uint8_t* start, const uint8_t* end) { AccountingAllocator allocator; PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr, kPrintLocals); } namespace { const char* RawOpcodeName(WasmOpcode opcode) { switch (opcode) { #define DECLARE_NAME_CASE(name, ...) \ case kExpr##name: \ return "kExpr" #name; FOREACH_OPCODE(DECLARE_NAME_CASE) #undef DECLARE_NAME_CASE default: break; } return "Unknown"; } const char* PrefixName(WasmOpcode prefix_opcode) { switch (prefix_opcode) { #define DECLARE_PREFIX_CASE(name, opcode) \ case k##name##Prefix: \ return "k" #name "Prefix"; FOREACH_PREFIX(DECLARE_PREFIX_CASE) #undef DECLARE_PREFIX_CASE default: return "Unknown prefix"; } } } // namespace bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, const WasmModule* module, PrintLocals print_locals) { StdoutStream os; return PrintRawWasmCode(allocator, body, module, print_locals, os); } bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, const WasmModule* module, PrintLocals print_locals, std::ostream& os, std::vector<int>* line_numbers) { Zone zone(allocator, ZONE_NAME); WasmFeatures unused_detected_features = WasmFeatures::None(); WasmDecoder<Decoder::NoValidationTag> decoder( &zone, module, WasmFeatures::All(), &unused_detected_features, body.sig, body.start, body.end); int line_nr = 0; constexpr int kNoByteCode = -1; // Print the function signature. if (body.sig) { os << "// signature: " << *body.sig << std::endl; if (line_numbers) line_numbers->push_back(kNoByteCode); ++line_nr; } // Print the local declarations. BodyLocalDecls decls; BytecodeIterator i(body.start, body.end, &decls, &zone); if (body.start != i.pc() && print_locals == kPrintLocals) { os << "// locals:"; if (decls.num_locals > 0) { ValueType type = decls.local_types[0]; uint32_t count = 0; for (size_t pos = 0; pos < decls.num_locals; ++pos) { if (decls.local_types[pos] == type) { ++count; } else { os << " " << count << " " << type.name(); type = decls.local_types[pos]; count = 1; } } os << " " << count << " " << type.name(); } os << std::endl; if (line_numbers) line_numbers->push_back(kNoByteCode); ++line_nr; for (const uint8_t* locals = body.start; locals < i.pc(); locals++) { os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ","; } os << std::endl; if (line_numbers) line_numbers->push_back(kNoByteCode); ++line_nr; } os << "// body:" << std::endl; if (line_numbers) line_numbers->push_back(kNoByteCode); ++line_nr; unsigned control_depth = 0; for (; i.has_next(); i.next()) { unsigned length = WasmDecoder<Decoder::NoValidationTag>::OpcodeLength(&decoder, i.pc()); unsigned offset = 1; WasmOpcode opcode = i.current(); WasmOpcode prefix = kExprUnreachable; bool has_prefix = WasmOpcodes::IsPrefixOpcode(opcode); if (has_prefix) { prefix = i.current(); opcode = i.prefixed_opcode(); offset = 2; } if (line_numbers) line_numbers->push_back(i.position()); if (opcode == kExprElse || opcode == kExprCatch || opcode == kExprCatchAll) { control_depth--; } int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64; // 64 whitespaces const char* padding = " "; os.write(padding, num_whitespaces); if (has_prefix) { os << PrefixName(prefix) << ", "; } if (WasmOpcodes::IsRelaxedSimdOpcode(opcode)) { // Expand multi-byte opcodes. os << "..."; offset += 1; } os << RawOpcodeName(opcode) << ","; if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock || opcode == kExprTry) { if (i.pc()[1] & 0x80) { auto [type, temp_length] = value_type_reader::read_value_type<Decoder::NoValidationTag>( &decoder, i.pc() + 1, WasmFeatures::All()); if (temp_length == 1) { os << type.name() << ","; } else { // TODO(manoskouk): Improve this for rtts and (nullable) refs. for (unsigned j = offset; j < length; ++j) { os << " 0x" << AsHex(i.pc()[j], 2) << ","; } } } else { for (unsigned j = offset; j < length; ++j) { os << " 0x" << AsHex(i.pc()[j], 2) << ","; } } } else { for (unsigned j = offset; j < length; ++j) { os << " 0x" << AsHex(i.pc()[j], 2) << ","; } } os << " // " << WasmOpcodes::OpcodeName(opcode); switch (opcode) { case kExprElse: case kExprCatch: case kExprCatchAll: os << " @" << i.pc_offset(); control_depth++; break; case kExprLoop: case kExprIf: case kExprBlock: case kExprTry: { BlockTypeImmediate imm(WasmFeatures::All(), &i, i.pc() + 1, Decoder::kNoValidation); os << " @" << i.pc_offset(); CHECK(decoder.Validate(i.pc() + 1, imm)); for (uint32_t j = 0; j < imm.out_arity(); j++) { os << " " << imm.out_type(j).name(); } control_depth++; break; } case kExprEnd: os << " @" << i.pc_offset(); control_depth--; break; case kExprBr: { BranchDepthImmediate imm(&i, i.pc() + 1, Decoder::kNoValidation); os << " depth=" << imm.depth; break; } case kExprBrIf: { BranchDepthImmediate imm(&i, i.pc() + 1, Decoder::kNoValidation); os << " depth=" << imm.depth; break; } case kExprBrTable: { BranchTableImmediate imm(&i, i.pc() + 1, Decoder::kNoValidation); os << " entries=" << imm.table_count; break; } case kExprCallIndirect: { CallIndirectImmediate imm(&i, i.pc() + 1, Decoder::kNoValidation); os << " sig #" << imm.sig_imm.index; CHECK(decoder.Validate(i.pc() + 1, imm)); os << ": " << *imm.sig; break; } case kExprCallRef: { SigIndexImmediate imm(&i, i.pc() + 1, Decoder::kNoValidation); CHECK(decoder.Validate(i.pc() + 1, imm)); os << ": " << *imm.sig; break; } case kExprCallFunction: { CallFunctionImmediate imm(&i, i.pc() + 1, Decoder::kNoValidation); os << " function #" << imm.index; CHECK(decoder.Validate(i.pc() + 1, imm)); os << ": " << *imm.sig; break; } default: break; } os << std::endl; ++line_nr; } DCHECK(!line_numbers || line_numbers->size() == static_cast<size_t>(line_nr)); USE(line_nr); return decoder.ok(); } BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, uint32_t num_locals, const uint8_t* start, const uint8_t* end, bool* loop_is_innermost) { WasmFeatures no_features = WasmFeatures::None(); WasmDecoder<Decoder::FullValidationTag> decoder( zone, nullptr, no_features, &no_features, nullptr, start, end, 0); return WasmDecoder<Decoder::FullValidationTag>::AnalyzeLoopAssignment( &decoder, start, num_locals, zone, loop_is_innermost); } } // namespace wasm } // namespace internal } // namespace v8