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