 Chromium Code Reviews
 Chromium Code Reviews Issue 2042633002:
  [interpreter] Ensure optimizations preserve source positions.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 2042633002:
  [interpreter] Ensure optimizations preserve source positions.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| OLD | NEW | 
|---|---|
| (Empty) | |
| 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 "test/cctest/interpreter/source-position-matcher.h" | |
| 6 | |
| 7 #include "src/interpreter/bytecode-array-iterator.h" | |
| 8 #include "src/objects-inl.h" | |
| 9 #include "src/objects.h" | |
| 10 | |
| 11 namespace v8 { | |
| 12 namespace internal { | |
| 13 namespace interpreter { | |
| 14 | |
| 15 // Comparer for PositionTableEntry instances. | |
| 16 struct PTECompare { | |
| 
rmcilroy
2016/06/07 09:46:11
I don't think it's worth abbreviating this given y
 
oth
2016/06/07 13:46:17
Done.
 | |
| 17 bool operator()(const PositionTableEntry& lhs, | |
| 18 const PositionTableEntry& rhs) { | |
| 19 int lhs_type_score = type_score(lhs); | |
| 20 int rhs_type_score = type_score(rhs); | |
| 21 if (lhs_type_score == rhs_type_score) { | |
| 22 return lhs.source_position < rhs.source_position; | |
| 23 } else { | |
| 24 return lhs_type_score < rhs_type_score; | |
| 25 } | |
| 26 } | |
| 27 | |
| 28 int type_score(const PositionTableEntry& entry) { | |
| 29 return entry.is_statement ? 1 : 0; | |
| 30 } | |
| 31 }; | |
| 32 | |
| 33 // | |
| 34 // The principles for comparing source positions in bytecode arrays | |
| 35 // are: | |
| 36 // | |
| 37 // 1. The number of statement positions must be the same in both. | |
| 38 // | |
| 39 // 2. Statement positions may be moved provide they do not affect the | |
| 40 // debuggers causal view of the v8 heap and local state. This means | |
| 41 // statement positions may be moved when their initial posiiton is | |
| 
rmcilroy
2016/06/07 09:46:11
/s/posiiton/position
 
oth
2016/06/07 13:46:17
Done.
 | |
| 42 // on bytecodes that manipulate the accumulator and temporary | |
| 43 // registers. | |
| 44 // | |
| 45 // 3. When duplicate expression positions are present, either may | |
| 46 // be dropped. | |
| 47 // | |
| 48 // 4. Expression positions may be applied to later bytecodes in the | |
| 49 // bytecode array if the current bytecode does not throw. | |
| 50 // | |
| 51 // 5. Expression positions may be dropped when they are applied to | |
| 52 // bytecodes that manipulate local frame state and immediately | |
| 53 // proceeded by another source position. | |
| 54 // | |
| 55 // 6. The relative ordering of source positions must be preserved. | |
| 56 // | |
| 57 bool SourcePositionMatcher::Match(Handle<BytecodeArray> original_bytecode, | |
| 58 Handle<BytecodeArray> optimized_bytecode) { | |
| 59 SourcePositionTableIterator original( | |
| 60 original_bytecode->source_position_table()); | |
| 61 SourcePositionTableIterator optimized( | |
| 62 optimized_bytecode->source_position_table()); | |
| 63 | |
| 64 int last_original_bytecode_offset = 0; | |
| 65 int last_optimized_bytecode_offset = 0; | |
| 66 | |
| 67 // Order list of expression positions (terminated by a statement | |
| 68 // position to ease validation). | |
| 
rmcilroy
2016/06/07 09:46:11
I think it's a bit confusing to terminate with the
 
oth
2016/06/07 13:46:17
Okay, done. The statement position is used as a ba
 | |
| 69 std::vector<PositionTableEntry> original_expression_entries; | |
| 70 std::vector<PositionTableEntry> optimized_expression_entries; | |
| 71 | |
| 72 while (true) { | |
| 73 MoveToNextStatement(&original, &original_expression_entries); | |
| 74 MoveToNextStatement(&optimized, &optimized_expression_entries); | |
| 75 | |
| 76 if (original.done() && optimized.done()) { | |
| 77 return true; | |
| 78 } else if (original.done()) { | |
| 79 printf("Source positions ended early on original bytecode."); | |
| 80 return false; | |
| 81 } else if (optimized.done()) { | |
| 82 printf("Source positions ended early on optimized bytecode."); | |
| 83 return false; | |
| 84 } | |
| 85 | |
| 86 if (NewExpressionPositionsInOptimized(&original_expression_entries, | |
| 
rmcilroy
2016/06/07 09:46:11
nit - HasNewExpressionPositionsInOptimized
 
oth
2016/06/07 13:46:17
Done.
 | |
| 87 &optimized_expression_entries)) { | |
| 88 printf("Optimized set has new expression positions.\n"); | |
| 89 return false; | |
| 90 } | |
| 91 | |
| 92 StripUnneededExpressionPositions(original_bytecode, | |
| 93 &original_expression_entries); | |
| 94 StripUnneededExpressionPositions(optimized_bytecode, | |
| 95 &optimized_expression_entries); | |
| 96 if (!CompareExpressionPositions(&original_expression_entries, | |
| 97 &optimized_expression_entries)) { | |
| 98 return false; | |
| 
rmcilroy
2016/06/07 09:46:11
nit - comment that message is printed in CompareEx
 
oth
2016/06/07 13:46:17
Done.
 | |
| 99 } | |
| 100 | |
| 101 // Check original and optimized have matching source positions. | |
| 102 if (original.source_position() != optimized.source_position()) { | |
| 103 printf("Statement source position mismatch %d != %d\n", | |
| 104 original.source_position(), optimized.source_position()); | |
| 105 return false; | |
| 106 } | |
| 107 | |
| 108 if (original.bytecode_offset() < last_original_bytecode_offset) { | |
| 109 printf("Original has bytecode offset running backwards %d < %d.\n", | |
| 110 original.bytecode_offset(), last_original_bytecode_offset); | |
| 111 return false; | |
| 112 } | |
| 113 last_original_bytecode_offset = original.bytecode_offset(); | |
| 114 | |
| 115 if (optimized.bytecode_offset() < last_optimized_bytecode_offset) { | |
| 116 printf("Optimized has bytecode offset running backwards %d < %d.\n", | |
| 117 optimized.bytecode_offset(), last_optimized_bytecode_offset); | |
| 118 return false; | |
| 119 } | |
| 120 last_optimized_bytecode_offset = optimized.bytecode_offset(); | |
| 121 | |
| 122 // TODO(oth): Can we compare statement positions are semantically | |
| 123 // equivalent? e.g. before a bytecode that has debugger observable | |
| 124 // effects. This is likely non-trivial. | |
| 125 } | |
| 126 | |
| 127 return true; | |
| 128 } | |
| 129 | |
| 130 bool SourcePositionMatcher::NewExpressionPositionsInOptimized( | |
| 131 const std::vector<PositionTableEntry>* const original_positions, | |
| 132 const std::vector<PositionTableEntry>* const optimized_positions) { | |
| 133 std::set<PositionTableEntry, PTECompare> original_set( | |
| 134 original_positions->begin(), original_positions->end()); | |
| 135 | |
| 136 bool retval = false; | |
| 137 for (auto optimized_position : *optimized_positions) { | |
| 138 if (original_set.find(optimized_position) == original_set.end()) { | |
| 139 printf("Optimized bytecode has new expression source position %d\n", | |
| 140 optimized_position.source_position); | |
| 141 retval = true; | |
| 142 } | |
| 143 } | |
| 144 return retval; | |
| 145 } | |
| 146 | |
| 147 bool SourcePositionMatcher::CompareExpressionPositions( | |
| 148 const std::vector<PositionTableEntry>* const original_positions, | |
| 149 const std::vector<PositionTableEntry>* const optimized_positions) { | |
| 150 if (original_positions->size() < 1 || | |
| 151 !original_positions->back().is_statement) { | |
| 152 printf( | |
| 153 "Original expression positions are not terminated by a statement.\n"); | |
| 154 return false; | |
| 155 } | |
| 156 | |
| 157 if (optimized_positions->size() < 1 || | |
| 158 !optimized_positions->back().is_statement) { | |
| 159 printf( | |
| 160 "Optimized expression positions are not terminated by a statement.\n"); | |
| 161 return false; | |
| 162 } | |
| 163 | |
| 164 if (original_positions->size() != optimized_positions->size()) { | |
| 165 printf( | |
| 166 "Optimized bytecode has different number of expression positions " | |
| 167 "%zu != %zu\n", | |
| 168 optimized_positions->size() - 1, original_positions->size() - 1); | |
| 169 printf("Original expression source positions"); | |
| 
rmcilroy
2016/06/07 09:46:11
Is some of this logging printfs? Maybe you should
 
oth
2016/06/07 13:46:17
I can't see anything in v8 tests that attempts to
 | |
| 170 for (size_t i = 0; i < original_positions->size() - 1; ++i) { | |
| 171 printf(" %d", original_positions->at(i).source_position); | |
| 172 } | |
| 173 printf("\nOptimized expression source positions"); | |
| 174 for (size_t i = 0; i < optimized_positions->size() - 1; ++i) { | |
| 175 printf(" %d", optimized_positions->at(i).source_position); | |
| 176 } | |
| 177 printf("\n"); | |
| 178 return false; | |
| 179 } | |
| 180 | |
| 181 for (size_t i = 0; i < original_positions->size() - 1; ++i) { | |
| 182 PositionTableEntry original = original_positions->at(i); | |
| 183 PositionTableEntry optimized = original_positions->at(i); | |
| 184 CHECK(original.source_position > 0); | |
| 185 if ((original.is_statement || optimized.is_statement) || | |
| 186 (original.source_position != optimized.source_position) || | |
| 187 (original.source_position < 0)) { | |
| 188 printf("Expression positions differ %d != %d\n", original.source_position, | |
| 189 optimized.source_position); | |
| 190 return false; | |
| 191 } | |
| 192 } | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 void SourcePositionMatcher::StripUnneededExpressionPositions( | |
| 197 Handle<BytecodeArray> bytecode_array, | |
| 198 std::vector<PositionTableEntry>* positions) { | |
| 199 size_t j = 0; | |
| 200 for (size_t i = 0; i < positions->size() - 1; ++i) { | |
| 201 CHECK(positions->at(i).source_position > 0 && | |
| 202 !positions->at(i).is_statement); | |
| 203 if (ExpressionPositionIsNeeded(bytecode_array, | |
| 204 positions->at(i).bytecode_offset, | |
| 205 positions->at(i + 1).bytecode_offset)) { | |
| 206 positions->at(j++) = positions->at(i); | |
| 207 } | |
| 208 } | |
| 209 positions->at(j++) = positions->back(); | |
| 210 positions->resize(j); | |
| 211 CHECK(positions->back().is_statement); | |
| 212 } | |
| 213 | |
| 214 bool SourcePositionMatcher::ExpressionPositionIsNeeded( | |
| 215 Handle<BytecodeArray> bytecode_array, int start_offset, int end_offset) { | |
| 216 CHECK_GT(end_offset, start_offset); | |
| 217 BytecodeArrayIterator iterator(bytecode_array); | |
| 218 while (iterator.current_offset() != start_offset) { | |
| 219 iterator.Advance(); | |
| 220 } | |
| 221 | |
| 222 while (iterator.current_offset() != end_offset) { | |
| 223 if (Bytecodes::IsWithoutExternalSideEffects(iterator.current_bytecode())) { | |
| 224 iterator.Advance(); | |
| 225 } else { | |
| 226 // Bytecode could throw so need an expression position. | |
| 227 CHECK(iterator.current_bytecode() != Bytecode::kStar); | |
| 
rmcilroy
2016/06/07 09:46:11
Not sure why this CHECK is here. It couldn't be St
 
oth
2016/06/07 13:46:17
It's just left over cruft from an earlier revision
 | |
| 228 return true; | |
| 229 } | |
| 230 } | |
| 231 return false; | |
| 232 } | |
| 233 | |
| 234 void SourcePositionMatcher::MoveToNextStatement( | |
| 235 SourcePositionTableIterator* iterator, | |
| 236 std::vector<PositionTableEntry>* positions) { | |
| 237 iterator->Advance(); | |
| 238 positions->clear(); | |
| 239 while (!iterator->done()) { | |
| 240 positions->push_back({iterator->bytecode_offset(), | |
| 241 iterator->source_position(), | |
| 242 iterator->is_statement()}); | |
| 243 if (iterator->is_statement()) { | |
| 244 break; | |
| 245 } | |
| 246 iterator->Advance(); | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 } // namespace interpreter | |
| 251 } // namespace internal | |
| 252 } // namespace v8 | |
| OLD | NEW |