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 |