source-position-table.cc revision f91f0611dbaf29ca0f1d4aecb357ce243a19d2fa
1// Copyright 2016 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 5#include "src/source-position-table.h" 6 7#include "src/log.h" 8#include "src/objects-inl.h" 9#include "src/objects.h" 10 11namespace v8 { 12namespace internal { 13 14// We'll use a simple encoding scheme to record the source positions. 15// Conceptually, each position consists of: 16// - code_offset: An integer index into the BytecodeArray or code. 17// - source_position: An integer index into the source string. 18// - position type: Each position is either a statement or an expression. 19// 20// The basic idea for the encoding is to use a variable-length integer coding, 21// where each byte contains 7 bits of payload data, and 1 'more' bit that 22// determines whether additional bytes follow. Additionally: 23// - we record the difference from the previous position, 24// - we just stuff one bit for the type into the code offset, 25// - we write least-significant bits first, 26// - we use zig-zag encoding to encode both positive and negative numbers. 27 28namespace { 29 30// Each byte is encoded as MoreBit | ValueBits. 31class MoreBit : public BitField8<bool, 7, 1> {}; 32class ValueBits : public BitField8<unsigned, 0, 7> {}; 33 34// Helper: Add the offsets from 'other' to 'value'. Also set is_statement. 35void AddAndSetEntry(PositionTableEntry& value, 36 const PositionTableEntry& other) { 37 value.code_offset += other.code_offset; 38 value.source_position += other.source_position; 39 value.is_statement = other.is_statement; 40} 41 42// Helper: Substract the offsets from 'other' from 'value'. 43void SubtractFromEntry(PositionTableEntry& value, 44 const PositionTableEntry& other) { 45 value.code_offset -= other.code_offset; 46 value.source_position -= other.source_position; 47} 48 49// Helper: Encode an integer. 50void EncodeInt(ZoneVector<byte>& bytes, int value) { 51 // Zig-zag encoding. 52 static const int kShift = kIntSize * kBitsPerByte - 1; 53 value = ((value << 1) ^ (value >> kShift)); 54 DCHECK_GE(value, 0); 55 unsigned int encoded = static_cast<unsigned int>(value); 56 bool more; 57 do { 58 more = encoded > ValueBits::kMax; 59 bytes.push_back(MoreBit::encode(more) | 60 ValueBits::encode(encoded & ValueBits::kMask)); 61 encoded >>= ValueBits::kSize; 62 } while (more); 63} 64 65// Encode a PositionTableEntry. 66void EncodeEntry(ZoneVector<byte>& bytes, const PositionTableEntry& entry) { 67 // We only accept ascending code offsets. 68 DCHECK(entry.code_offset >= 0); 69 // Since code_offset is not negative, we use sign to encode is_statement. 70 EncodeInt(bytes, 71 entry.is_statement ? entry.code_offset : -entry.code_offset - 1); 72 EncodeInt(bytes, entry.source_position); 73} 74 75// Helper: Decode an integer. 76void DecodeInt(ByteArray* bytes, int* index, int* v) { 77 byte current; 78 int shift = 0; 79 int decoded = 0; 80 bool more; 81 do { 82 current = bytes->get((*index)++); 83 decoded |= ValueBits::decode(current) << shift; 84 more = MoreBit::decode(current); 85 shift += ValueBits::kSize; 86 } while (more); 87 DCHECK_GE(decoded, 0); 88 decoded = (decoded >> 1) ^ (-(decoded & 1)); 89 *v = decoded; 90} 91 92void DecodeEntry(ByteArray* bytes, int* index, PositionTableEntry* entry) { 93 int tmp; 94 DecodeInt(bytes, index, &tmp); 95 if (tmp >= 0) { 96 entry->is_statement = true; 97 entry->code_offset = tmp; 98 } else { 99 entry->is_statement = false; 100 entry->code_offset = -(tmp + 1); 101 } 102 DecodeInt(bytes, index, &entry->source_position); 103} 104 105} // namespace 106 107SourcePositionTableBuilder::SourcePositionTableBuilder( 108 Zone* zone, SourcePositionTableBuilder::RecordingMode mode) 109 : mode_(mode), 110 bytes_(zone), 111#ifdef ENABLE_SLOW_DCHECKS 112 raw_entries_(zone), 113#endif 114 previous_() { 115} 116 117void SourcePositionTableBuilder::AddPosition(size_t code_offset, 118 int source_position, 119 bool is_statement) { 120 if (Omit()) return; 121 int offset = static_cast<int>(code_offset); 122 AddEntry({offset, source_position, is_statement}); 123} 124 125void SourcePositionTableBuilder::AddEntry(const PositionTableEntry& entry) { 126 PositionTableEntry tmp(entry); 127 SubtractFromEntry(tmp, previous_); 128 EncodeEntry(bytes_, tmp); 129 previous_ = entry; 130#ifdef ENABLE_SLOW_DCHECKS 131 raw_entries_.push_back(entry); 132#endif 133} 134 135Handle<ByteArray> SourcePositionTableBuilder::ToSourcePositionTable( 136 Isolate* isolate, Handle<AbstractCode> code) { 137 if (bytes_.empty()) return isolate->factory()->empty_byte_array(); 138 DCHECK(!Omit()); 139 140 Handle<ByteArray> table = isolate->factory()->NewByteArray( 141 static_cast<int>(bytes_.size()), TENURED); 142 143 MemCopy(table->GetDataStartAddress(), &*bytes_.begin(), bytes_.size()); 144 145 LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(*code, *table)); 146 147#ifdef ENABLE_SLOW_DCHECKS 148 // Brute force testing: Record all positions and decode 149 // the entire table to verify they are identical. 150 auto raw = raw_entries_.begin(); 151 for (SourcePositionTableIterator encoded(*table); !encoded.done(); 152 encoded.Advance(), raw++) { 153 DCHECK(raw != raw_entries_.end()); 154 DCHECK_EQ(encoded.code_offset(), raw->code_offset); 155 DCHECK_EQ(encoded.source_position(), raw->source_position); 156 DCHECK_EQ(encoded.is_statement(), raw->is_statement); 157 } 158 DCHECK(raw == raw_entries_.end()); 159 // No additional source positions after creating the table. 160 mode_ = OMIT_SOURCE_POSITIONS; 161#endif 162 return table; 163} 164 165SourcePositionTableIterator::SourcePositionTableIterator(ByteArray* byte_array) 166 : table_(byte_array), index_(0), current_() { 167 Advance(); 168} 169 170void SourcePositionTableIterator::Advance() { 171 DCHECK(!done()); 172 DCHECK(index_ >= 0 && index_ <= table_->length()); 173 if (index_ == table_->length()) { 174 index_ = kDone; 175 } else { 176 PositionTableEntry tmp; 177 DecodeEntry(table_, &index_, &tmp); 178 AddAndSetEntry(current_, tmp); 179 } 180} 181 182} // namespace internal 183} // namespace v8 184