11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/codegen/source-position-table.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/base/export-template.h" 81cb0ef41Sopenharmony_ci#include "src/base/logging.h" 91cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h" 101cb0ef41Sopenharmony_ci#include "src/heap/local-factory-inl.h" 111cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 121cb0ef41Sopenharmony_ci#include "src/objects/objects.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci// We'll use a simple encoding scheme to record the source positions. 181cb0ef41Sopenharmony_ci// Conceptually, each position consists of: 191cb0ef41Sopenharmony_ci// - code_offset: An integer index into the BytecodeArray or code. 201cb0ef41Sopenharmony_ci// - source_position: An integer index into the source string. 211cb0ef41Sopenharmony_ci// - position type: Each position is either a statement or an expression. 221cb0ef41Sopenharmony_ci// 231cb0ef41Sopenharmony_ci// The basic idea for the encoding is to use a variable-length integer coding, 241cb0ef41Sopenharmony_ci// where each byte contains 7 bits of payload data, and 1 'more' bit that 251cb0ef41Sopenharmony_ci// determines whether additional bytes follow. Additionally: 261cb0ef41Sopenharmony_ci// - we record the difference from the previous position, 271cb0ef41Sopenharmony_ci// - we just stuff one bit for the type into the code offset, 281cb0ef41Sopenharmony_ci// - we write least-significant bits first, 291cb0ef41Sopenharmony_ci// - we use zig-zag encoding to encode both positive and negative numbers. 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_cinamespace { 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci// Each byte is encoded as MoreBit | ValueBits. 341cb0ef41Sopenharmony_ciusing MoreBit = base::BitField8<bool, 7, 1>; 351cb0ef41Sopenharmony_ciusing ValueBits = base::BitField8<unsigned, 0, 7>; 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci// Helper: Add the offsets from 'other' to 'value'. Also set is_statement. 381cb0ef41Sopenharmony_civoid AddAndSetEntry(PositionTableEntry* value, 391cb0ef41Sopenharmony_ci const PositionTableEntry& other) { 401cb0ef41Sopenharmony_ci value->code_offset += other.code_offset; 411cb0ef41Sopenharmony_ci DCHECK_IMPLIES(value->code_offset != kFunctionEntryBytecodeOffset, 421cb0ef41Sopenharmony_ci value->code_offset >= 0); 431cb0ef41Sopenharmony_ci value->source_position += other.source_position; 441cb0ef41Sopenharmony_ci DCHECK_LE(0, value->source_position); 451cb0ef41Sopenharmony_ci value->is_statement = other.is_statement; 461cb0ef41Sopenharmony_ci} 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci// Helper: Subtract the offsets from 'other' from 'value'. 491cb0ef41Sopenharmony_civoid SubtractFromEntry(PositionTableEntry* value, 501cb0ef41Sopenharmony_ci const PositionTableEntry& other) { 511cb0ef41Sopenharmony_ci value->code_offset -= other.code_offset; 521cb0ef41Sopenharmony_ci value->source_position -= other.source_position; 531cb0ef41Sopenharmony_ci} 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci// Helper: Encode an integer. 561cb0ef41Sopenharmony_citemplate <typename T> 571cb0ef41Sopenharmony_civoid EncodeInt(ZoneVector<byte>* bytes, T value) { 581cb0ef41Sopenharmony_ci using unsigned_type = typename std::make_unsigned<T>::type; 591cb0ef41Sopenharmony_ci // Zig-zag encoding. 601cb0ef41Sopenharmony_ci static constexpr int kShift = sizeof(T) * kBitsPerByte - 1; 611cb0ef41Sopenharmony_ci value = ((static_cast<unsigned_type>(value) << 1) ^ (value >> kShift)); 621cb0ef41Sopenharmony_ci DCHECK_GE(value, 0); 631cb0ef41Sopenharmony_ci unsigned_type encoded = static_cast<unsigned_type>(value); 641cb0ef41Sopenharmony_ci bool more; 651cb0ef41Sopenharmony_ci do { 661cb0ef41Sopenharmony_ci more = encoded > ValueBits::kMax; 671cb0ef41Sopenharmony_ci byte current = 681cb0ef41Sopenharmony_ci MoreBit::encode(more) | ValueBits::encode(encoded & ValueBits::kMask); 691cb0ef41Sopenharmony_ci bytes->push_back(current); 701cb0ef41Sopenharmony_ci encoded >>= ValueBits::kSize; 711cb0ef41Sopenharmony_ci } while (more); 721cb0ef41Sopenharmony_ci} 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci// Encode a PositionTableEntry. 751cb0ef41Sopenharmony_civoid EncodeEntry(ZoneVector<byte>* bytes, const PositionTableEntry& entry) { 761cb0ef41Sopenharmony_ci // We only accept ascending code offsets. 771cb0ef41Sopenharmony_ci DCHECK_LE(0, entry.code_offset); 781cb0ef41Sopenharmony_ci // All but the first entry must be *strictly* ascending (no two entries for 791cb0ef41Sopenharmony_ci // the same position). 801cb0ef41Sopenharmony_ci // TODO(11496): This DCHECK fails tests. 811cb0ef41Sopenharmony_ci // DCHECK_IMPLIES(!bytes->empty(), entry.code_offset > 0); 821cb0ef41Sopenharmony_ci // Since code_offset is not negative, we use sign to encode is_statement. 831cb0ef41Sopenharmony_ci EncodeInt(bytes, 841cb0ef41Sopenharmony_ci entry.is_statement ? entry.code_offset : -entry.code_offset - 1); 851cb0ef41Sopenharmony_ci EncodeInt(bytes, entry.source_position); 861cb0ef41Sopenharmony_ci} 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci// Helper: Decode an integer. 891cb0ef41Sopenharmony_citemplate <typename T> 901cb0ef41Sopenharmony_ciT DecodeInt(base::Vector<const byte> bytes, int* index) { 911cb0ef41Sopenharmony_ci byte current; 921cb0ef41Sopenharmony_ci int shift = 0; 931cb0ef41Sopenharmony_ci T decoded = 0; 941cb0ef41Sopenharmony_ci bool more; 951cb0ef41Sopenharmony_ci do { 961cb0ef41Sopenharmony_ci current = bytes[(*index)++]; 971cb0ef41Sopenharmony_ci decoded |= static_cast<typename std::make_unsigned<T>::type>( 981cb0ef41Sopenharmony_ci ValueBits::decode(current)) 991cb0ef41Sopenharmony_ci << shift; 1001cb0ef41Sopenharmony_ci more = MoreBit::decode(current); 1011cb0ef41Sopenharmony_ci shift += ValueBits::kSize; 1021cb0ef41Sopenharmony_ci } while (more); 1031cb0ef41Sopenharmony_ci DCHECK_GE(decoded, 0); 1041cb0ef41Sopenharmony_ci decoded = (decoded >> 1) ^ (-(decoded & 1)); 1051cb0ef41Sopenharmony_ci return decoded; 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_civoid DecodeEntry(base::Vector<const byte> bytes, int* index, 1091cb0ef41Sopenharmony_ci PositionTableEntry* entry) { 1101cb0ef41Sopenharmony_ci int tmp = DecodeInt<int>(bytes, index); 1111cb0ef41Sopenharmony_ci if (tmp >= 0) { 1121cb0ef41Sopenharmony_ci entry->is_statement = true; 1131cb0ef41Sopenharmony_ci entry->code_offset = tmp; 1141cb0ef41Sopenharmony_ci } else { 1151cb0ef41Sopenharmony_ci entry->is_statement = false; 1161cb0ef41Sopenharmony_ci entry->code_offset = -(tmp + 1); 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci entry->source_position = DecodeInt<int64_t>(bytes, index); 1191cb0ef41Sopenharmony_ci} 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_cibase::Vector<const byte> VectorFromByteArray(ByteArray byte_array) { 1221cb0ef41Sopenharmony_ci return base::Vector<const byte>(byte_array.GetDataStartAddress(), 1231cb0ef41Sopenharmony_ci byte_array.length()); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS 1271cb0ef41Sopenharmony_civoid CheckTableEquals(const ZoneVector<PositionTableEntry>& raw_entries, 1281cb0ef41Sopenharmony_ci SourcePositionTableIterator* encoded) { 1291cb0ef41Sopenharmony_ci // Brute force testing: Record all positions and decode 1301cb0ef41Sopenharmony_ci // the entire table to verify they are identical. 1311cb0ef41Sopenharmony_ci auto raw = raw_entries.begin(); 1321cb0ef41Sopenharmony_ci for (; !encoded->done(); encoded->Advance(), raw++) { 1331cb0ef41Sopenharmony_ci DCHECK(raw != raw_entries.end()); 1341cb0ef41Sopenharmony_ci DCHECK_EQ(encoded->code_offset(), raw->code_offset); 1351cb0ef41Sopenharmony_ci DCHECK_EQ(encoded->source_position().raw(), raw->source_position); 1361cb0ef41Sopenharmony_ci DCHECK_EQ(encoded->is_statement(), raw->is_statement); 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci DCHECK(raw == raw_entries.end()); 1391cb0ef41Sopenharmony_ci} 1401cb0ef41Sopenharmony_ci#endif 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci} // namespace 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ciSourcePositionTableBuilder::SourcePositionTableBuilder( 1451cb0ef41Sopenharmony_ci Zone* zone, SourcePositionTableBuilder::RecordingMode mode) 1461cb0ef41Sopenharmony_ci : mode_(mode), 1471cb0ef41Sopenharmony_ci bytes_(zone), 1481cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS 1491cb0ef41Sopenharmony_ci raw_entries_(zone), 1501cb0ef41Sopenharmony_ci#endif 1511cb0ef41Sopenharmony_ci previous_() { 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_civoid SourcePositionTableBuilder::AddPosition(size_t code_offset, 1551cb0ef41Sopenharmony_ci SourcePosition source_position, 1561cb0ef41Sopenharmony_ci bool is_statement) { 1571cb0ef41Sopenharmony_ci if (Omit()) return; 1581cb0ef41Sopenharmony_ci DCHECK(source_position.IsKnown()); 1591cb0ef41Sopenharmony_ci int offset = static_cast<int>(code_offset); 1601cb0ef41Sopenharmony_ci AddEntry({offset, source_position.raw(), is_statement}); 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_civoid SourcePositionTableBuilder::AddEntry(const PositionTableEntry& entry) { 1641cb0ef41Sopenharmony_ci PositionTableEntry tmp(entry); 1651cb0ef41Sopenharmony_ci SubtractFromEntry(&tmp, previous_); 1661cb0ef41Sopenharmony_ci EncodeEntry(&bytes_, tmp); 1671cb0ef41Sopenharmony_ci previous_ = entry; 1681cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS 1691cb0ef41Sopenharmony_ci raw_entries_.push_back(entry); 1701cb0ef41Sopenharmony_ci#endif 1711cb0ef41Sopenharmony_ci} 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_citemplate <typename IsolateT> 1741cb0ef41Sopenharmony_ciHandle<ByteArray> SourcePositionTableBuilder::ToSourcePositionTable( 1751cb0ef41Sopenharmony_ci IsolateT* isolate) { 1761cb0ef41Sopenharmony_ci if (bytes_.empty()) return isolate->factory()->empty_byte_array(); 1771cb0ef41Sopenharmony_ci DCHECK(!Omit()); 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci Handle<ByteArray> table = isolate->factory()->NewByteArray( 1801cb0ef41Sopenharmony_ci static_cast<int>(bytes_.size()), AllocationType::kOld); 1811cb0ef41Sopenharmony_ci MemCopy(table->GetDataStartAddress(), bytes_.data(), bytes_.size()); 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS 1841cb0ef41Sopenharmony_ci // Brute force testing: Record all positions and decode 1851cb0ef41Sopenharmony_ci // the entire table to verify they are identical. 1861cb0ef41Sopenharmony_ci SourcePositionTableIterator it( 1871cb0ef41Sopenharmony_ci *table, SourcePositionTableIterator::kAll, 1881cb0ef41Sopenharmony_ci SourcePositionTableIterator::kDontSkipFunctionEntry); 1891cb0ef41Sopenharmony_ci CheckTableEquals(raw_entries_, &it); 1901cb0ef41Sopenharmony_ci // No additional source positions after creating the table. 1911cb0ef41Sopenharmony_ci mode_ = OMIT_SOURCE_POSITIONS; 1921cb0ef41Sopenharmony_ci#endif 1931cb0ef41Sopenharmony_ci return table; 1941cb0ef41Sopenharmony_ci} 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 1971cb0ef41Sopenharmony_ci Handle<ByteArray> SourcePositionTableBuilder::ToSourcePositionTable( 1981cb0ef41Sopenharmony_ci Isolate* isolate); 1991cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 2001cb0ef41Sopenharmony_ci Handle<ByteArray> SourcePositionTableBuilder::ToSourcePositionTable( 2011cb0ef41Sopenharmony_ci LocalIsolate* isolate); 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_cibase::OwnedVector<byte> 2041cb0ef41Sopenharmony_ciSourcePositionTableBuilder::ToSourcePositionTableVector() { 2051cb0ef41Sopenharmony_ci if (bytes_.empty()) return base::OwnedVector<byte>(); 2061cb0ef41Sopenharmony_ci DCHECK(!Omit()); 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci base::OwnedVector<byte> table = base::OwnedVector<byte>::Of(bytes_); 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS 2111cb0ef41Sopenharmony_ci // Brute force testing: Record all positions and decode 2121cb0ef41Sopenharmony_ci // the entire table to verify they are identical. 2131cb0ef41Sopenharmony_ci SourcePositionTableIterator it( 2141cb0ef41Sopenharmony_ci table.as_vector(), SourcePositionTableIterator::kAll, 2151cb0ef41Sopenharmony_ci SourcePositionTableIterator::kDontSkipFunctionEntry); 2161cb0ef41Sopenharmony_ci CheckTableEquals(raw_entries_, &it); 2171cb0ef41Sopenharmony_ci // No additional source positions after creating the table. 2181cb0ef41Sopenharmony_ci mode_ = OMIT_SOURCE_POSITIONS; 2191cb0ef41Sopenharmony_ci#endif 2201cb0ef41Sopenharmony_ci return table; 2211cb0ef41Sopenharmony_ci} 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_civoid SourcePositionTableIterator::Initialize() { 2241cb0ef41Sopenharmony_ci Advance(); 2251cb0ef41Sopenharmony_ci if (function_entry_filter_ == kSkipFunctionEntry && 2261cb0ef41Sopenharmony_ci current_.code_offset == kFunctionEntryBytecodeOffset && !done()) { 2271cb0ef41Sopenharmony_ci Advance(); 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci} 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ciSourcePositionTableIterator::SourcePositionTableIterator( 2321cb0ef41Sopenharmony_ci ByteArray byte_array, IterationFilter iteration_filter, 2331cb0ef41Sopenharmony_ci FunctionEntryFilter function_entry_filter) 2341cb0ef41Sopenharmony_ci : raw_table_(VectorFromByteArray(byte_array)), 2351cb0ef41Sopenharmony_ci iteration_filter_(iteration_filter), 2361cb0ef41Sopenharmony_ci function_entry_filter_(function_entry_filter) { 2371cb0ef41Sopenharmony_ci Initialize(); 2381cb0ef41Sopenharmony_ci} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ciSourcePositionTableIterator::SourcePositionTableIterator( 2411cb0ef41Sopenharmony_ci Handle<ByteArray> byte_array, IterationFilter iteration_filter, 2421cb0ef41Sopenharmony_ci FunctionEntryFilter function_entry_filter) 2431cb0ef41Sopenharmony_ci : table_(byte_array), 2441cb0ef41Sopenharmony_ci iteration_filter_(iteration_filter), 2451cb0ef41Sopenharmony_ci function_entry_filter_(function_entry_filter) { 2461cb0ef41Sopenharmony_ci Initialize(); 2471cb0ef41Sopenharmony_ci#ifdef DEBUG 2481cb0ef41Sopenharmony_ci // We can enable allocation because we keep the table in a handle. 2491cb0ef41Sopenharmony_ci no_gc.Release(); 2501cb0ef41Sopenharmony_ci#endif // DEBUG 2511cb0ef41Sopenharmony_ci} 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ciSourcePositionTableIterator::SourcePositionTableIterator( 2541cb0ef41Sopenharmony_ci base::Vector<const byte> bytes, IterationFilter iteration_filter, 2551cb0ef41Sopenharmony_ci FunctionEntryFilter function_entry_filter) 2561cb0ef41Sopenharmony_ci : raw_table_(bytes), 2571cb0ef41Sopenharmony_ci iteration_filter_(iteration_filter), 2581cb0ef41Sopenharmony_ci function_entry_filter_(function_entry_filter) { 2591cb0ef41Sopenharmony_ci Initialize(); 2601cb0ef41Sopenharmony_ci#ifdef DEBUG 2611cb0ef41Sopenharmony_ci // We can enable allocation because the underlying vector does not move. 2621cb0ef41Sopenharmony_ci no_gc.Release(); 2631cb0ef41Sopenharmony_ci#endif // DEBUG 2641cb0ef41Sopenharmony_ci} 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_civoid SourcePositionTableIterator::Advance() { 2671cb0ef41Sopenharmony_ci base::Vector<const byte> bytes = 2681cb0ef41Sopenharmony_ci table_.is_null() ? raw_table_ : VectorFromByteArray(*table_); 2691cb0ef41Sopenharmony_ci DCHECK(!done()); 2701cb0ef41Sopenharmony_ci DCHECK(index_ >= 0 && index_ <= bytes.length()); 2711cb0ef41Sopenharmony_ci bool filter_satisfied = false; 2721cb0ef41Sopenharmony_ci while (!done() && !filter_satisfied) { 2731cb0ef41Sopenharmony_ci if (index_ >= bytes.length()) { 2741cb0ef41Sopenharmony_ci index_ = kDone; 2751cb0ef41Sopenharmony_ci } else { 2761cb0ef41Sopenharmony_ci PositionTableEntry tmp; 2771cb0ef41Sopenharmony_ci DecodeEntry(bytes, &index_, &tmp); 2781cb0ef41Sopenharmony_ci AddAndSetEntry(¤t_, tmp); 2791cb0ef41Sopenharmony_ci SourcePosition p = source_position(); 2801cb0ef41Sopenharmony_ci filter_satisfied = 2811cb0ef41Sopenharmony_ci (iteration_filter_ == kAll) || 2821cb0ef41Sopenharmony_ci (iteration_filter_ == kJavaScriptOnly && p.IsJavaScript()) || 2831cb0ef41Sopenharmony_ci (iteration_filter_ == kExternalOnly && p.IsExternal()); 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci} 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ci} // namespace internal 2891cb0ef41Sopenharmony_ci} // namespace v8 290