OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 #include <map> | |
6 | 7 |
7 #include "src/v8.h" | 8 #include "src/v8.h" |
8 | 9 |
9 #include "src/ast/ast.h" | 10 #include "src/ast/ast.h" |
10 #include "src/ast/ast-expression-visitor.h" | 11 #include "src/ast/ast-expression-visitor.h" |
11 #include "src/ast/scopes.h" | 12 #include "src/ast/scopes.h" |
12 #include "src/parsing/parser.h" | 13 #include "src/parsing/parser.h" |
13 #include "src/parsing/rewriter.h" | 14 #include "src/parsing/rewriter.h" |
14 #include "test/cctest/cctest.h" | 15 #include "test/cctest/cctest.h" |
15 #include "test/cctest/expression-type-collector.h" | 16 #include "test/cctest/expression-type-collector.h" |
16 #include "test/cctest/expression-type-collector-macros.h" | 17 #include "test/cctest/expression-type-collector-macros.h" |
17 | 18 |
18 using namespace v8::internal; | 19 using namespace v8::internal; |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 static void CollectTypes(HandleAndZoneScope* handles, const char* source, | 23 class NodeTypeCounter : public AstExpressionVisitor { |
23 ZoneVector<ExpressionTypeEntry>* dst) { | 24 public: |
24 i::Isolate* isolate = CcTest::i_isolate(); | 25 typedef std::map<AstNode::NodeType, int> Counters; |
25 i::Factory* factory = isolate->factory(); | |
26 | 26 |
27 i::Handle<i::String> source_code = | 27 NodeTypeCounter(Isolate* isolate, Expression* expr, Counters* counts) |
28 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); | 28 : AstExpressionVisitor(isolate, expr), counts_(counts) {} |
29 | 29 |
30 i::Handle<i::Script> script = factory->NewScript(source_code); | 30 protected: |
31 void VisitExpression(Expression* expr) override { | |
32 (*counts_)[expr->node_type()]++; | |
33 } | |
31 | 34 |
32 i::ParseInfo info(handles->main_zone(), script); | 35 private: |
33 i::Parser parser(&info); | 36 Counters* counts_; |
34 info.set_global(); | 37 }; |
35 info.set_lazy(false); | |
36 info.set_allow_lazy_parsing(false); | |
37 info.set_toplevel(true); | |
38 | |
39 CHECK(i::Compiler::ParseAndAnalyze(&info)); | |
40 | |
41 ExpressionTypeCollector( | |
42 isolate, | |
43 info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun(), dst) | |
44 .Run(); | |
45 } | |
46 | 38 |
47 } // namespace | 39 } // namespace |
48 | 40 |
49 | 41 TEST(VisitExpression) { |
50 TEST(VisitExpressions) { | |
51 v8::V8::Initialize(); | |
52 HandleAndZoneScope handles; | |
53 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | |
54 const char test_function[] = | 42 const char test_function[] = |
55 "function GeometricMean(stdlib, foreign, buffer) {\n" | 43 "function GeometricMean(stdlib, foreign, buffer) {\n" |
56 " \"use asm\";\n" | 44 " \"use asm\";\n" |
57 "\n" | 45 "\n" |
58 " var exp = stdlib.Math.exp;\n" | 46 " var exp = stdlib.Math.exp;\n" |
59 " var log = stdlib.Math.log;\n" | 47 " var log = stdlib.Math.log;\n" |
60 " var values = new stdlib.Float64Array(buffer);\n" | 48 " var values = new stdlib.Float64Array(buffer);\n" |
61 "\n" | 49 "\n" |
62 " function logSum(start, end) {\n" | 50 " function logSum(start, end) {\n" |
63 " start = start|0;\n" | 51 " start = start|0;\n" |
(...skipping 13 matching lines...) Expand all Loading... | |
77 " function geometricMean(start, end) {\n" | 65 " function geometricMean(start, end) {\n" |
78 " start = start|0;\n" | 66 " start = start|0;\n" |
79 " end = end|0;\n" | 67 " end = end|0;\n" |
80 "\n" | 68 "\n" |
81 " return +exp(+logSum(start, end) / +((end - start)|0));\n" | 69 " return +exp(+logSum(start, end) / +((end - start)|0));\n" |
82 " }\n" | 70 " }\n" |
83 "\n" | 71 "\n" |
84 " return { geometricMean: geometricMean };\n" | 72 " return { geometricMean: geometricMean };\n" |
85 "}\n"; | 73 "}\n"; |
86 | 74 |
87 CollectTypes(&handles, test_function, &types); | 75 // Parse + compile test_function, and extract the AST node for it. |
88 CHECK_TYPES_BEGIN { | |
89 // function logSum | |
90 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
91 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
92 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
93 CHECK_VAR(start, Bounds::Unbounded()); | |
94 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
95 CHECK_VAR(start, Bounds::Unbounded()); | |
96 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
97 } | |
98 } | |
99 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
100 CHECK_VAR(end, Bounds::Unbounded()); | |
101 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
102 CHECK_VAR(end, Bounds::Unbounded()); | |
103 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
104 } | |
105 } | |
106 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
107 CHECK_VAR(sum, Bounds::Unbounded()); | |
108 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
109 } | |
110 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
111 CHECK_VAR(p, Bounds::Unbounded()); | |
112 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
113 } | |
114 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
115 CHECK_VAR(q, Bounds::Unbounded()); | |
116 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
117 } | |
118 // for (p = start << 3, q = end << 3; | |
119 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
120 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
121 CHECK_VAR(p, Bounds::Unbounded()); | |
122 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
123 CHECK_VAR(start, Bounds::Unbounded()); | |
124 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
125 } | |
126 } | |
127 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
128 CHECK_VAR(q, Bounds::Unbounded()); | |
129 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
130 CHECK_VAR(end, Bounds::Unbounded()); | |
131 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
132 } | |
133 } | |
134 } | |
135 // (p|0) < (q|0); | |
136 CHECK_EXPR(CompareOperation, Bounds::Unbounded()) { | |
137 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
138 CHECK_VAR(p, Bounds::Unbounded()); | |
139 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
140 } | |
141 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
142 CHECK_VAR(q, Bounds::Unbounded()); | |
143 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
144 } | |
145 } | |
146 // p = (p + 8)|0) {\n" | |
147 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
148 CHECK_VAR(p, Bounds::Unbounded()); | |
149 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
150 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
151 CHECK_VAR(p, Bounds::Unbounded()); | |
152 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
153 } | |
154 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
155 } | |
156 } | |
157 // sum = sum + +log(values[p>>3]); | |
158 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
159 CHECK_VAR(sum, Bounds::Unbounded()); | |
160 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
161 CHECK_VAR(sum, Bounds::Unbounded()); | |
162 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
163 CHECK_EXPR(Call, Bounds::Unbounded()) { | |
164 CHECK_VAR(log, Bounds::Unbounded()); | |
165 CHECK_EXPR(Property, Bounds::Unbounded()) { | |
166 CHECK_VAR(values, Bounds::Unbounded()); | |
167 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
168 CHECK_VAR(p, Bounds::Unbounded()); | |
169 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
170 } | |
171 } | |
172 } | |
173 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
174 } | |
175 } | |
176 } | |
177 // return +sum; | |
178 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
179 CHECK_VAR(sum, Bounds::Unbounded()); | |
180 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
181 } | |
182 } | |
183 // function geometricMean | |
184 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
185 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
186 CHECK_VAR(start, Bounds::Unbounded()); | |
187 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
188 CHECK_VAR(start, Bounds::Unbounded()); | |
189 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
190 } | |
191 } | |
192 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
193 CHECK_VAR(end, Bounds::Unbounded()); | |
194 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
195 CHECK_VAR(end, Bounds::Unbounded()); | |
196 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
197 } | |
198 } | |
199 // return +exp(+logSum(start, end) / +((end - start)|0)); | |
200 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
201 CHECK_EXPR(Call, Bounds::Unbounded()) { | |
202 CHECK_VAR(exp, Bounds::Unbounded()); | |
203 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
204 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
205 CHECK_EXPR(Call, Bounds::Unbounded()) { | |
206 CHECK_VAR(logSum, Bounds::Unbounded()); | |
207 CHECK_VAR(start, Bounds::Unbounded()); | |
208 CHECK_VAR(end, Bounds::Unbounded()); | |
209 } | |
210 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
211 } | |
212 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
213 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
214 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
215 CHECK_VAR(end, Bounds::Unbounded()); | |
216 CHECK_VAR(start, Bounds::Unbounded()); | |
217 } | |
218 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
219 } | |
220 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
221 } | |
222 } | |
223 } | |
224 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
225 } | |
226 } | |
227 // "use asm"; | |
228 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
229 // var exp = stdlib.Math.exp; | |
230 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
231 CHECK_VAR(exp, Bounds::Unbounded()); | |
232 CHECK_EXPR(Property, Bounds::Unbounded()) { | |
233 CHECK_EXPR(Property, Bounds::Unbounded()) { | |
234 CHECK_VAR(stdlib, Bounds::Unbounded()); | |
235 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
236 } | |
237 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
238 } | |
239 } | |
240 // var log = stdlib.Math.log; | |
241 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
242 CHECK_VAR(log, Bounds::Unbounded()); | |
243 CHECK_EXPR(Property, Bounds::Unbounded()) { | |
244 CHECK_EXPR(Property, Bounds::Unbounded()) { | |
245 CHECK_VAR(stdlib, Bounds::Unbounded()); | |
246 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
247 } | |
248 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
249 } | |
250 } | |
251 // var values = new stdlib.Float64Array(buffer); | |
252 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
253 CHECK_VAR(values, Bounds::Unbounded()); | |
254 CHECK_EXPR(CallNew, Bounds::Unbounded()) { | |
255 CHECK_EXPR(Property, Bounds::Unbounded()) { | |
256 CHECK_VAR(stdlib, Bounds::Unbounded()); | |
257 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
258 } | |
259 CHECK_VAR(buffer, Bounds::Unbounded()); | |
260 } | |
261 } | |
262 // return { geometricMean: geometricMean }; | |
263 CHECK_EXPR(ObjectLiteral, Bounds::Unbounded()) { | |
264 CHECK_VAR(geometricMean, Bounds::Unbounded()); | |
265 } | |
266 } | |
267 } | |
268 CHECK_TYPES_END | |
269 } | |
270 | |
271 | |
272 TEST(VisitConditional) { | |
273 v8::V8::Initialize(); | 76 v8::V8::Initialize(); |
274 HandleAndZoneScope handles; | 77 HandleAndZoneScope handles; |
275 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | 78 i::Isolate* isolate = CcTest::i_isolate(); |
276 // Check that traversing the ternary operator works. | 79 i::Handle<i::String> source_code = |
277 const char test_function[] = | 80 isolate->factory() |
278 "function foo() {\n" | 81 ->NewStringFromUtf8(i::CStrVector(test_function)) |
279 " var a, b, c;\n" | 82 .ToHandleChecked(); |
280 " var x = a ? b : c;\n" | 83 i::Handle<i::Script> script = isolate->factory()->NewScript(source_code); |
281 "}\n"; | 84 i::ParseInfo info(handles.main_zone(), script); |
282 CollectTypes(&handles, test_function, &types); | 85 i::Parser parser(&info); |
283 CHECK_TYPES_BEGIN { | 86 info.set_global(); |
284 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | 87 info.set_lazy(false); |
285 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | 88 info.set_allow_lazy_parsing(false); |
286 CHECK_VAR(x, Bounds::Unbounded()); | 89 info.set_toplevel(true); |
287 CHECK_EXPR(Conditional, Bounds::Unbounded()) { | 90 CHECK(i::Compiler::ParseAndAnalyze(&info)); |
288 CHECK_VAR(a, Bounds::Unbounded()); | 91 Expression* test_function_expr = |
289 CHECK_VAR(b, Bounds::Unbounded()); | 92 info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun(); |
290 CHECK_VAR(c, Bounds::Unbounded()); | 93 |
291 } | 94 // Run NodeTypeCounter and sanity check counts for 3 expression types, |
292 } | 95 // and for overall # of types found. |
bradnelson
2016/05/12 15:43:45
Yeah that's better, this was overkill at the time.
| |
293 } | 96 NodeTypeCounter::Counters counts; |
294 } | 97 NodeTypeCounter(isolate, test_function_expr, &counts).Run(); |
295 CHECK_TYPES_END | 98 CHECK_EQ(21, counts[AstNode::kBinaryOperation]); |
99 CHECK_EQ(26, counts[AstNode::kLiteral]); | |
100 CHECK_EQ(3, counts[AstNode::kFunctionLiteral]); | |
101 CHECK_EQ(10, counts.size()); | |
296 } | 102 } |
297 | |
298 | |
299 TEST(VisitEmptyForStatment) { | |
300 v8::V8::Initialize(); | |
301 HandleAndZoneScope handles; | |
302 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | |
303 // Check that traversing an empty for statement works. | |
304 const char test_function[] = | |
305 "function foo() {\n" | |
306 " for (;;) {}\n" | |
307 "}\n"; | |
308 CollectTypes(&handles, test_function, &types); | |
309 CHECK_TYPES_BEGIN { | |
310 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {} | |
311 } | |
312 CHECK_TYPES_END | |
313 } | |
314 | |
315 | |
316 TEST(VisitSwitchStatment) { | |
317 v8::V8::Initialize(); | |
318 HandleAndZoneScope handles; | |
319 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | |
320 // Check that traversing a switch with a default works. | |
321 const char test_function[] = | |
322 "function foo() {\n" | |
323 " switch (0) { case 1: break; default: break; }\n" | |
324 "}\n"; | |
325 CollectTypes(&handles, test_function, &types); | |
326 CHECK_TYPES_BEGIN { | |
327 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
328 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
329 CHECK_VAR(.switch_tag, Bounds::Unbounded()); | |
330 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
331 } | |
332 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
333 CHECK_VAR(.switch_tag, Bounds::Unbounded()); | |
334 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
335 } | |
336 } | |
337 CHECK_TYPES_END | |
338 } | |
339 | |
340 | |
341 TEST(VisitThrow) { | |
342 v8::V8::Initialize(); | |
343 HandleAndZoneScope handles; | |
344 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | |
345 const char test_function[] = | |
346 "function foo() {\n" | |
347 " throw 123;\n" | |
348 "}\n"; | |
349 CollectTypes(&handles, test_function, &types); | |
350 CHECK_TYPES_BEGIN { | |
351 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
352 CHECK_EXPR(Throw, Bounds::Unbounded()) { | |
353 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
354 } | |
355 } | |
356 } | |
357 CHECK_TYPES_END | |
358 } | |
359 | |
360 | |
361 TEST(VisitYield) { | |
362 v8::V8::Initialize(); | |
363 HandleAndZoneScope handles; | |
364 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | |
365 const char test_function[] = | |
366 "function* foo() {\n" | |
367 " yield 123;\n" | |
368 "}\n"; | |
369 CollectTypes(&handles, test_function, &types); | |
370 CHECK_TYPES_BEGIN { | |
371 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
372 // Implicit initial yield | |
373 CHECK_EXPR(Yield, Bounds::Unbounded()) { | |
374 CHECK_VAR(.generator_object, Bounds::Unbounded()); | |
375 CHECK_EXPR(Assignment, Bounds::Unbounded()) { | |
376 CHECK_VAR(.generator_object, Bounds::Unbounded()); | |
377 CHECK_EXPR(CallRuntime, Bounds::Unbounded()) { | |
378 CHECK_EXPR(ThisFunction, Bounds::Unbounded()); | |
379 CHECK_EXPR(VariableProxy, Bounds::Unbounded()); | |
380 } | |
381 } | |
382 } | |
383 // Explicit yield (argument wrapped with CreateIterResultObject) | |
384 CHECK_EXPR(Yield, Bounds::Unbounded()) { | |
385 CHECK_VAR(.generator_object, Bounds::Unbounded()); | |
386 CHECK_EXPR(CallRuntime, Bounds::Unbounded()) { | |
387 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
388 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
389 } | |
390 } | |
391 // Argument to implicit final return | |
392 CHECK_EXPR(CallRuntime, Bounds::Unbounded()) { // CreateIterResultObject | |
393 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
394 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
395 } | |
396 // Implicit finally clause | |
397 CHECK_EXPR(CallRuntime, Bounds::Unbounded()) { | |
398 CHECK_VAR(.generator_object, Bounds::Unbounded()); | |
399 } | |
400 } | |
401 } | |
402 CHECK_TYPES_END | |
403 } | |
404 | |
405 | |
406 TEST(VisitSkipping) { | |
407 v8::V8::Initialize(); | |
408 HandleAndZoneScope handles; | |
409 ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); | |
410 const char test_function[] = | |
411 "function foo(x) {\n" | |
412 " return (x + x) + 1;\n" | |
413 "}\n"; | |
414 CollectTypes(&handles, test_function, &types); | |
415 CHECK_TYPES_BEGIN { | |
416 CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { | |
417 CHECK_EXPR(BinaryOperation, Bounds::Unbounded()) { | |
418 // Skip x + x | |
419 CHECK_SKIP(); | |
420 CHECK_EXPR(Literal, Bounds::Unbounded()); | |
421 } | |
422 } | |
423 } | |
424 CHECK_TYPES_END | |
425 } | |
OLD | NEW |