[presubmit] Enable readability/namespace linter checking.
[platform/upstream/v8.git] / test / cctest / test-asm-validator.cc
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
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/ast.h"
8 #include "src/ast-expression-visitor.h"
9 #include "src/parser.h"
10 #include "src/rewriter.h"
11 #include "src/scopes.h"
12 #include "src/typing-asm.h"
13 #include "src/zone-type-cache.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
18 // Macros for function types.
19 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone))
20 #define FUNC_I_TYPE Bounds(Type::Function(cache.kInt32, zone))
21 #define FUNC_F_TYPE Bounds(Type::Function(cache.kFloat32, zone))
22 #define FUNC_D_TYPE Bounds(Type::Function(cache.kFloat64, zone))
23 #define FUNC_D2D_TYPE \
24   Bounds(Type::Function(cache.kFloat64, cache.kFloat64, zone))
25 #define FUNC_N2F_TYPE \
26   Bounds(Type::Function(cache.kFloat32, Type::Number(), zone))
27 #define FUNC_I2I_TYPE Bounds(Type::Function(cache.kInt32, cache.kInt32, zone))
28 #define FUNC_II2D_TYPE \
29   Bounds(Type::Function(cache.kFloat64, cache.kInt32, cache.kInt32, zone))
30 #define FUNC_II2I_TYPE \
31   Bounds(Type::Function(cache.kInt32, cache.kInt32, cache.kInt32, zone))
32 #define FUNC_DD2D_TYPE \
33   Bounds(Type::Function(cache.kFloat64, cache.kFloat64, cache.kFloat64, zone))
34 #define FUNC_N2N_TYPE \
35   Bounds(Type::Function(Type::Number(), Type::Number(), zone))
36
37 // Macros for array types.
38 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kFloat64, zone))
39 #define FUNC_I2I_ARRAY_TYPE \
40   Bounds(Type::Array(Type::Function(cache.kInt32, cache.kInt32, zone), zone))
41
42 using namespace v8::internal;
43
44 namespace {
45
46 std::string Validate(Zone* zone, const char* source,
47                      ZoneVector<ExpressionTypeEntry>* types) {
48   i::Isolate* isolate = CcTest::i_isolate();
49   i::Factory* factory = isolate->factory();
50
51   i::Handle<i::String> source_code =
52       factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked();
53
54   i::Handle<i::Script> script = factory->NewScript(source_code);
55
56   i::ParseInfo info(zone, script);
57   i::Parser parser(&info);
58   parser.set_allow_harmony_arrow_functions(true);
59   parser.set_allow_harmony_sloppy(true);
60   info.set_global();
61   info.set_lazy(false);
62   info.set_allow_lazy_parsing(false);
63   info.set_toplevel(true);
64
65   CHECK(i::Compiler::ParseAndAnalyze(&info));
66
67   FunctionLiteral* root =
68       info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun();
69   AsmTyper typer(isolate, zone, *script, root);
70   if (typer.Validate()) {
71     ExpressionTypeCollector(isolate, zone, root, types).Run();
72     return "";
73   } else {
74     return typer.error_message();
75   }
76 }
77
78 }  // namespace
79
80
81 TEST(ValidateMinimum) {
82   const char test_function[] =
83       "function GeometricMean(stdlib, foreign, buffer) {\n"
84       "  \"use asm\";\n"
85       "\n"
86       "  var exp = stdlib.Math.exp;\n"
87       "  var log = stdlib.Math.log;\n"
88       "  var values = new stdlib.Float64Array(buffer);\n"
89       "\n"
90       "  function logSum(start, end) {\n"
91       "    start = start|0;\n"
92       "    end = end|0;\n"
93       "\n"
94       "    var sum = 0.0, p = 0, q = 0;\n"
95       "\n"
96       "    // asm.js forces byte addressing of the heap by requiring shifting "
97       "by 3\n"
98       "    for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {\n"
99       "      sum = sum + +log(values[p>>3]);\n"
100       "    }\n"
101       "\n"
102       "    return +sum;\n"
103       "  }\n"
104       "\n"
105       " function geometricMean(start, end) {\n"
106       "    start = start|0;\n"
107       "    end = end|0;\n"
108       "\n"
109       "    return +exp(+logSum(start, end) / +((end - start)|0));\n"
110       "  }\n"
111       "\n"
112       "  return { geometricMean: geometricMean };\n"
113       "}\n";
114
115   v8::V8::Initialize();
116   HandleAndZoneScope handles;
117   Zone* zone = handles.main_zone();
118   ZoneVector<ExpressionTypeEntry> types(zone);
119   CHECK_EQ("", Validate(zone, test_function, &types));
120   ZoneTypeCache cache;
121
122   CHECK_TYPES_BEGIN {
123     // Module.
124     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
125       // function logSum
126       CHECK_EXPR(FunctionLiteral, FUNC_II2D_TYPE) {
127         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
128           CHECK_VAR(start, Bounds(cache.kInt32));
129           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
130             CHECK_VAR(start, Bounds(cache.kInt32));
131             CHECK_EXPR(Literal, Bounds(cache.kInt32));
132           }
133         }
134         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
135           CHECK_VAR(end, Bounds(cache.kInt32));
136           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
137             CHECK_VAR(end, Bounds(cache.kInt32));
138             CHECK_EXPR(Literal, Bounds(cache.kInt32));
139           }
140         }
141         CHECK_EXPR(Assignment, Bounds(cache.kFloat64)) {
142           CHECK_VAR(sum, Bounds(cache.kFloat64));
143           CHECK_EXPR(Literal, Bounds(cache.kFloat64));
144         }
145         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
146           CHECK_VAR(p, Bounds(cache.kInt32));
147           CHECK_EXPR(Literal, Bounds(cache.kInt32));
148         }
149         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
150           CHECK_VAR(q, Bounds(cache.kInt32));
151           CHECK_EXPR(Literal, Bounds(cache.kInt32));
152         }
153         // for (p = start << 3, q = end << 3;
154         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
155           CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
156             CHECK_VAR(p, Bounds(cache.kInt32));
157             CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
158               CHECK_VAR(start, Bounds(cache.kInt32));
159               CHECK_EXPR(Literal, Bounds(cache.kInt32));
160             }
161           }
162           CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
163             CHECK_VAR(q, Bounds(cache.kInt32));
164             CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
165               CHECK_VAR(end, Bounds(cache.kInt32));
166               CHECK_EXPR(Literal, Bounds(cache.kInt32));
167             }
168           }
169         }
170         // (p|0) < (q|0);
171         CHECK_EXPR(CompareOperation, Bounds(cache.kInt32)) {
172           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
173             CHECK_VAR(p, Bounds(cache.kInt32));
174             CHECK_EXPR(Literal, Bounds(cache.kInt32));
175           }
176           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
177             CHECK_VAR(q, Bounds(cache.kInt32));
178             CHECK_EXPR(Literal, Bounds(cache.kInt32));
179           }
180         }
181         // p = (p + 8)|0) {\n"
182         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
183           CHECK_VAR(p, Bounds(cache.kInt32));
184           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
185             CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
186               CHECK_VAR(p, Bounds(cache.kInt32));
187               CHECK_EXPR(Literal, Bounds(cache.kInt32));
188             }
189             CHECK_EXPR(Literal, Bounds(cache.kInt32));
190           }
191         }
192         // sum = sum + +log(values[p>>3]);
193         CHECK_EXPR(Assignment, Bounds(cache.kFloat64)) {
194           CHECK_VAR(sum, Bounds(cache.kFloat64));
195           CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
196             CHECK_VAR(sum, Bounds(cache.kFloat64));
197             CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
198               CHECK_EXPR(Call, Bounds(cache.kFloat64)) {
199                 CHECK_VAR(log, FUNC_D2D_TYPE);
200                 CHECK_EXPR(Property, Bounds(cache.kFloat64)) {
201                   CHECK_VAR(values, FLOAT64_ARRAY_TYPE);
202                   CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
203                     CHECK_VAR(p, Bounds(cache.kInt32));
204                     CHECK_EXPR(Literal, Bounds(cache.kInt32));
205                   }
206                 }
207               }
208               CHECK_EXPR(Literal, Bounds(cache.kFloat64));
209             }
210           }
211         }
212         // return +sum;
213         CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
214           CHECK_VAR(sum, Bounds(cache.kFloat64));
215           CHECK_EXPR(Literal, Bounds(cache.kFloat64));
216         }
217       }
218       // function geometricMean
219       CHECK_EXPR(FunctionLiteral, FUNC_II2D_TYPE) {
220         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
221           CHECK_VAR(start, Bounds(cache.kInt32));
222           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
223             CHECK_VAR(start, Bounds(cache.kInt32));
224             CHECK_EXPR(Literal, Bounds(cache.kInt32));
225           }
226         }
227         CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
228           CHECK_VAR(end, Bounds(cache.kInt32));
229           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
230             CHECK_VAR(end, Bounds(cache.kInt32));
231             CHECK_EXPR(Literal, Bounds(cache.kInt32));
232           }
233         }
234         // return +exp(+logSum(start, end) / +((end - start)|0));
235         CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
236           CHECK_EXPR(Call, Bounds(cache.kFloat64)) {
237             CHECK_VAR(exp, FUNC_D2D_TYPE);
238             CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
239               CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
240                 CHECK_EXPR(Call, Bounds(cache.kFloat64)) {
241                   CHECK_VAR(logSum, FUNC_II2D_TYPE);
242                   CHECK_VAR(start, Bounds(cache.kInt32));
243                   CHECK_VAR(end, Bounds(cache.kInt32));
244                 }
245                 CHECK_EXPR(Literal, Bounds(cache.kFloat64));
246               }
247               CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
248                 CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
249                   CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
250                     CHECK_VAR(end, Bounds(cache.kInt32));
251                     CHECK_VAR(start, Bounds(cache.kInt32));
252                   }
253                   CHECK_EXPR(Literal, Bounds(cache.kInt32));
254                 }
255                 CHECK_EXPR(Literal, Bounds(cache.kFloat64));
256               }
257             }
258           }
259           CHECK_EXPR(Literal, Bounds(cache.kFloat64));
260         }
261       }
262       // "use asm";
263       CHECK_EXPR(Literal, Bounds(Type::String()));
264       // var exp = stdlib.Math.exp;
265       CHECK_EXPR(Assignment, FUNC_D2D_TYPE) {
266         CHECK_VAR(exp, FUNC_D2D_TYPE);
267         CHECK_EXPR(Property, FUNC_D2D_TYPE) {
268           CHECK_EXPR(Property, Bounds::Unbounded()) {
269             CHECK_VAR(stdlib, Bounds::Unbounded());
270             CHECK_EXPR(Literal, Bounds::Unbounded());
271           }
272           CHECK_EXPR(Literal, Bounds::Unbounded());
273         }
274       }
275       // var log = stdlib.Math.log;
276       CHECK_EXPR(Assignment, FUNC_D2D_TYPE) {
277         CHECK_VAR(log, FUNC_D2D_TYPE);
278         CHECK_EXPR(Property, FUNC_D2D_TYPE) {
279           CHECK_EXPR(Property, Bounds::Unbounded()) {
280             CHECK_VAR(stdlib, Bounds::Unbounded());
281             CHECK_EXPR(Literal, Bounds::Unbounded());
282           }
283           CHECK_EXPR(Literal, Bounds::Unbounded());
284         }
285       }
286       // var values = new stdlib.Float64Array(buffer);
287       CHECK_EXPR(Assignment, FLOAT64_ARRAY_TYPE) {
288         CHECK_VAR(values, FLOAT64_ARRAY_TYPE);
289         CHECK_EXPR(CallNew, FLOAT64_ARRAY_TYPE) {
290           CHECK_EXPR(Property, Bounds::Unbounded()) {
291             CHECK_VAR(stdlib, Bounds::Unbounded());
292             CHECK_EXPR(Literal, Bounds::Unbounded());
293           }
294           CHECK_VAR(buffer, Bounds::Unbounded());
295         }
296       }
297       // return { geometricMean: geometricMean };
298       CHECK_EXPR(ObjectLiteral, Bounds::Unbounded()) {
299         CHECK_VAR(geometricMean, FUNC_II2D_TYPE);
300       }
301     }
302   }
303   CHECK_TYPES_END
304 }
305
306
307 #define HARNESS_STDLIB()                 \
308   "var Infinity = stdlib.Infinity;\n"    \
309   "var NaN = stdlib.NaN;\n"              \
310   "var acos = stdlib.Math.acos;\n"       \
311   "var asin = stdlib.Math.asin;\n"       \
312   "var atan = stdlib.Math.atan;\n"       \
313   "var cos = stdlib.Math.cos;\n"         \
314   "var sin = stdlib.Math.sin;\n"         \
315   "var tan = stdlib.Math.tan;\n"         \
316   "var exp = stdlib.Math.exp;\n"         \
317   "var log = stdlib.Math.log;\n"         \
318   "var ceil = stdlib.Math.ceil;\n"       \
319   "var floor = stdlib.Math.floor;\n"     \
320   "var sqrt = stdlib.Math.sqrt;\n"       \
321   "var min = stdlib.Math.min;\n"         \
322   "var max = stdlib.Math.max;\n"         \
323   "var atan2 = stdlib.Math.atan2;\n"     \
324   "var pow = stdlib.Math.pow;\n"         \
325   "var abs = stdlib.Math.abs;\n"         \
326   "var imul = stdlib.Math.imul;\n"       \
327   "var fround = stdlib.Math.fround;\n"   \
328   "var E = stdlib.Math.E;\n"             \
329   "var LN10 = stdlib.Math.LN10;\n"       \
330   "var LN2 = stdlib.Math.LN2;\n"         \
331   "var LOG2E = stdlib.Math.LOG2E;\n"     \
332   "var LOG10E = stdlib.Math.LOG10E;\n"   \
333   "var PI = stdlib.Math.PI;\n"           \
334   "var SQRT1_2 = stdlib.Math.SQRT1_2;\n" \
335   "var SQRT2 = stdlib.Math.SQRT2;\n"
336
337
338 #define HARNESS_HEAP()                           \
339   "var u8 = new stdlib.Uint8Array(buffer);\n"    \
340   "var i8 = new stdlib.Int8Array(buffer);\n"     \
341   "var u16 = new stdlib.Uint16Array(buffer);\n"  \
342   "var i16 = new stdlib.Int16Array(buffer);\n"   \
343   "var u32 = new stdlib.Uint32Array(buffer);\n"  \
344   "var i32 = new stdlib.Int32Array(buffer);\n"   \
345   "var f32 = new stdlib.Float32Array(buffer);\n" \
346   "var f64 = new stdlib.Float64Array(buffer);\n"
347
348
349 #define HARNESS_PREAMBLE()                           \
350   const char test_function[] =                       \
351       "function Module(stdlib, foreign, buffer) {\n" \
352       "\"use asm\";\n" HARNESS_STDLIB() HARNESS_HEAP()
353
354
355 #define HARNESS_POSTAMBLE() \
356   "return { foo: foo };\n"  \
357   "}\n";
358
359
360 #define CHECK_VAR_MATH_SHORTCUT(name, type)       \
361   CHECK_EXPR(Assignment, type) {                  \
362     CHECK_VAR(name, type);                        \
363     CHECK_EXPR(Property, type) {                  \
364       CHECK_EXPR(Property, Bounds::Unbounded()) { \
365         CHECK_VAR(stdlib, Bounds::Unbounded());   \
366         CHECK_EXPR(Literal, Bounds::Unbounded()); \
367       }                                           \
368       CHECK_EXPR(Literal, Bounds::Unbounded());   \
369     }                                             \
370   }
371
372
373 #define CHECK_VAR_SHORTCUT(name, type)          \
374   CHECK_EXPR(Assignment, type) {                \
375     CHECK_VAR(name, type);                      \
376     CHECK_EXPR(Property, type) {                \
377       CHECK_VAR(stdlib, Bounds::Unbounded());   \
378       CHECK_EXPR(Literal, Bounds::Unbounded()); \
379     }                                           \
380   }
381
382
383 #define CHECK_VAR_NEW_SHORTCUT(name, type)        \
384   CHECK_EXPR(Assignment, type) {                  \
385     CHECK_VAR(name, type);                        \
386     CHECK_EXPR(CallNew, type) {                   \
387       CHECK_EXPR(Property, Bounds::Unbounded()) { \
388         CHECK_VAR(stdlib, Bounds::Unbounded());   \
389         CHECK_EXPR(Literal, Bounds::Unbounded()); \
390       }                                           \
391       CHECK_VAR(buffer, Bounds::Unbounded());     \
392     }                                             \
393   }
394
395
396 namespace {
397
398 void CheckStdlibShortcuts(Zone* zone, ZoneVector<ExpressionTypeEntry>& types,
399                           size_t& index, int& depth, ZoneTypeCache& cache) {
400   // var exp = stdlib.*; (D * 12)
401   CHECK_VAR_SHORTCUT(Infinity, Bounds(cache.kFloat64));
402   CHECK_VAR_SHORTCUT(NaN, Bounds(cache.kFloat64));
403   // var x = stdlib.Math.x;  D2D
404   CHECK_VAR_MATH_SHORTCUT(acos, FUNC_D2D_TYPE);
405   CHECK_VAR_MATH_SHORTCUT(asin, FUNC_D2D_TYPE);
406   CHECK_VAR_MATH_SHORTCUT(atan, FUNC_D2D_TYPE);
407   CHECK_VAR_MATH_SHORTCUT(cos, FUNC_D2D_TYPE);
408   CHECK_VAR_MATH_SHORTCUT(sin, FUNC_D2D_TYPE);
409   CHECK_VAR_MATH_SHORTCUT(tan, FUNC_D2D_TYPE);
410   CHECK_VAR_MATH_SHORTCUT(exp, FUNC_D2D_TYPE);
411   CHECK_VAR_MATH_SHORTCUT(log, FUNC_D2D_TYPE);
412   CHECK_VAR_MATH_SHORTCUT(ceil, FUNC_D2D_TYPE);
413   CHECK_VAR_MATH_SHORTCUT(floor, FUNC_D2D_TYPE);
414   CHECK_VAR_MATH_SHORTCUT(sqrt, FUNC_D2D_TYPE);
415   // var exp = stdlib.Math.*; (DD2D * 12)
416   CHECK_VAR_MATH_SHORTCUT(min, FUNC_DD2D_TYPE);
417   CHECK_VAR_MATH_SHORTCUT(max, FUNC_DD2D_TYPE);
418   CHECK_VAR_MATH_SHORTCUT(atan2, FUNC_DD2D_TYPE);
419   CHECK_VAR_MATH_SHORTCUT(pow, FUNC_DD2D_TYPE);
420   // Special ones.
421   CHECK_VAR_MATH_SHORTCUT(abs, FUNC_N2N_TYPE);
422   CHECK_VAR_MATH_SHORTCUT(imul, FUNC_II2I_TYPE);
423   CHECK_VAR_MATH_SHORTCUT(fround, FUNC_N2F_TYPE);
424   // var exp = stdlib.Math.*; (D * 12)
425   CHECK_VAR_MATH_SHORTCUT(E, Bounds(cache.kFloat64));
426   CHECK_VAR_MATH_SHORTCUT(LN10, Bounds(cache.kFloat64));
427   CHECK_VAR_MATH_SHORTCUT(LN2, Bounds(cache.kFloat64));
428   CHECK_VAR_MATH_SHORTCUT(LOG2E, Bounds(cache.kFloat64));
429   CHECK_VAR_MATH_SHORTCUT(LOG10E, Bounds(cache.kFloat64));
430   CHECK_VAR_MATH_SHORTCUT(PI, Bounds(cache.kFloat64));
431   CHECK_VAR_MATH_SHORTCUT(SQRT1_2, Bounds(cache.kFloat64));
432   CHECK_VAR_MATH_SHORTCUT(SQRT2, Bounds(cache.kFloat64));
433   // var values = new stdlib.*Array(buffer);
434   CHECK_VAR_NEW_SHORTCUT(u8, Bounds(cache.kUint8Array));
435   CHECK_VAR_NEW_SHORTCUT(i8, Bounds(cache.kInt8Array));
436   CHECK_VAR_NEW_SHORTCUT(u16, Bounds(cache.kUint16Array));
437   CHECK_VAR_NEW_SHORTCUT(i16, Bounds(cache.kInt16Array));
438   CHECK_VAR_NEW_SHORTCUT(u32, Bounds(cache.kUint32Array));
439   CHECK_VAR_NEW_SHORTCUT(i32, Bounds(cache.kInt32Array));
440   CHECK_VAR_NEW_SHORTCUT(f32, Bounds(cache.kFloat32Array));
441   CHECK_VAR_NEW_SHORTCUT(f64, Bounds(cache.kFloat64Array));
442 }
443
444 }  // namespace
445
446
447 #define CHECK_FUNC_TYPES_BEGIN(func)                   \
448   HARNESS_PREAMBLE()                                   \
449   func "\n" HARNESS_POSTAMBLE();                       \
450                                                        \
451   v8::V8::Initialize();                                \
452   HandleAndZoneScope handles;                          \
453   Zone* zone = handles.main_zone();                    \
454   ZoneVector<ExpressionTypeEntry> types(zone);         \
455   CHECK_EQ("", Validate(zone, test_function, &types)); \
456   ZoneTypeCache cache;                                 \
457                                                        \
458   CHECK_TYPES_BEGIN {                                  \
459     /* Module. */                                      \
460     CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) {
461 #define CHECK_FUNC_TYPES_END_1()               \
462   /* "use asm"; */                             \
463   CHECK_EXPR(Literal, Bounds(Type::String())); \
464   /* stdlib shortcuts. */                      \
465   CheckStdlibShortcuts(zone, types, index, depth, cache);
466
467
468 #define CHECK_FUNC_TYPES_END_2()                   \
469   /* return { foo: foo }; */                       \
470   CHECK_EXPR(ObjectLiteral, Bounds::Unbounded()) { \
471     CHECK_VAR(foo, FUNC_V_TYPE);                   \
472   }                                                \
473   }                                                \
474   }                                                \
475   CHECK_TYPES_END
476
477
478 #define CHECK_FUNC_TYPES_END \
479   CHECK_FUNC_TYPES_END_1();  \
480   CHECK_FUNC_TYPES_END_2();
481
482
483 #define CHECK_FUNC_ERROR(func, message)        \
484   HARNESS_PREAMBLE()                           \
485   func "\n" HARNESS_POSTAMBLE();               \
486                                                \
487   v8::V8::Initialize();                        \
488   HandleAndZoneScope handles;                  \
489   Zone* zone = handles.main_zone();            \
490   ZoneVector<ExpressionTypeEntry> types(zone); \
491   CHECK_EQ(message, Validate(zone, test_function, &types));
492
493
494 TEST(BareHarness) {
495   CHECK_FUNC_TYPES_BEGIN("function foo() {}") {
496     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {}
497   }
498   CHECK_FUNC_TYPES_END
499 }
500
501
502 TEST(ReturnVoid) {
503   CHECK_FUNC_TYPES_BEGIN(
504       "function bar() { return; }\n"
505       "function foo() { bar(); }") {
506     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
507       // return undefined;
508       CHECK_EXPR(Literal, Bounds(Type::Undefined()));
509     }
510     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
511       CHECK_EXPR(Call, Bounds(Type::Undefined())) {
512         CHECK_VAR(bar, FUNC_V_TYPE);
513       }
514     }
515   }
516   CHECK_FUNC_TYPES_END
517 }
518
519
520 TEST(ReturnInt32Literal) {
521   CHECK_FUNC_TYPES_BEGIN(
522       "function bar() { return 1; }\n"
523       "function foo() { bar(); }") {
524     CHECK_EXPR(FunctionLiteral, FUNC_I_TYPE) {
525       // return 1;
526       CHECK_EXPR(Literal, Bounds(cache.kInt32));
527     }
528     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
529       CHECK_EXPR(Call, Bounds(cache.kInt32)) { CHECK_VAR(bar, FUNC_I_TYPE); }
530     }
531   }
532   CHECK_FUNC_TYPES_END
533 }
534
535
536 TEST(ReturnFloat64Literal) {
537   CHECK_FUNC_TYPES_BEGIN(
538       "function bar() { return 1.0; }\n"
539       "function foo() { bar(); }") {
540     CHECK_EXPR(FunctionLiteral, FUNC_D_TYPE) {
541       // return 1.0;
542       CHECK_EXPR(Literal, Bounds(cache.kFloat64));
543     }
544     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
545       CHECK_EXPR(Call, Bounds(cache.kFloat64)) { CHECK_VAR(bar, FUNC_D_TYPE); }
546     }
547   }
548   CHECK_FUNC_TYPES_END
549 }
550
551
552 TEST(ReturnFloat32Literal) {
553   CHECK_FUNC_TYPES_BEGIN(
554       "function bar() { return fround(1.0); }\n"
555       "function foo() { bar(); }") {
556     CHECK_EXPR(FunctionLiteral, FUNC_F_TYPE) {
557       // return fround(1.0);
558       CHECK_EXPR(Call, Bounds(cache.kFloat32)) {
559         CHECK_VAR(fround, FUNC_N2F_TYPE);
560         CHECK_EXPR(Literal, Bounds(cache.kFloat64));
561       }
562     }
563     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
564       CHECK_EXPR(Call, Bounds(cache.kFloat32)) { CHECK_VAR(bar, FUNC_F_TYPE); }
565     }
566   }
567   CHECK_FUNC_TYPES_END
568 }
569
570
571 TEST(ReturnFloat64Var) {
572   CHECK_FUNC_TYPES_BEGIN(
573       "function bar() { var x = 1.0; return +x; }\n"
574       "function foo() { bar(); }") {
575     CHECK_EXPR(FunctionLiteral, FUNC_D_TYPE) {
576       // return 1.0;
577       CHECK_EXPR(Assignment, Bounds(cache.kFloat64)) {
578         CHECK_VAR(x, Bounds(cache.kFloat64));
579         CHECK_EXPR(Literal, Bounds(cache.kFloat64));
580       }
581       // return 1.0;
582       CHECK_EXPR(BinaryOperation, Bounds(cache.kFloat64)) {
583         CHECK_VAR(x, Bounds(cache.kFloat64));
584         CHECK_EXPR(Literal, Bounds(cache.kFloat64));
585       }
586     }
587     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
588       CHECK_EXPR(Call, Bounds(cache.kFloat64)) { CHECK_VAR(bar, FUNC_D_TYPE); }
589     }
590   }
591   CHECK_FUNC_TYPES_END
592 }
593
594
595 TEST(Addition2) {
596   CHECK_FUNC_TYPES_BEGIN(
597       "function bar() { var x = 1; var y = 2; return (x+y)|0; }\n"
598       "function foo() { bar(); }") {
599     CHECK_EXPR(FunctionLiteral, FUNC_I_TYPE) {
600       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
601         CHECK_VAR(x, Bounds(cache.kInt32));
602         CHECK_EXPR(Literal, Bounds(cache.kInt32));
603       }
604       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
605         CHECK_VAR(y, Bounds(cache.kInt32));
606         CHECK_EXPR(Literal, Bounds(cache.kInt32));
607       }
608       CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
609         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
610           CHECK_VAR(x, Bounds(cache.kInt32));
611           CHECK_VAR(y, Bounds(cache.kInt32));
612         }
613         CHECK_EXPR(Literal, Bounds(cache.kInt32));
614       }
615     }
616     CHECK_SKIP();
617   }
618   CHECK_FUNC_TYPES_END
619 }
620
621
622 TEST(Addition4) {
623   CHECK_FUNC_TYPES_BEGIN(
624       "function bar() { var x = 1; var y = 2; return (x+y+x+y)|0; }\n"
625       "function foo() { bar(); }") {
626     CHECK_EXPR(FunctionLiteral, FUNC_I_TYPE) {
627       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
628         CHECK_VAR(x, Bounds(cache.kInt32));
629         CHECK_EXPR(Literal, Bounds(cache.kInt32));
630       }
631       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
632         CHECK_VAR(y, Bounds(cache.kInt32));
633         CHECK_EXPR(Literal, Bounds(cache.kInt32));
634       }
635       CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
636         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
637           CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
638             CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
639               CHECK_VAR(x, Bounds(cache.kInt32));
640               CHECK_VAR(y, Bounds(cache.kInt32));
641             }
642             CHECK_VAR(x, Bounds(cache.kInt32));
643           }
644           CHECK_VAR(y, Bounds(cache.kInt32));
645         }
646         CHECK_EXPR(Literal, Bounds(cache.kInt32));
647       }
648     }
649     CHECK_SKIP();
650   }
651   CHECK_FUNC_TYPES_END
652 }
653
654
655 TEST(Multiplication2) {
656   CHECK_FUNC_ERROR(
657       "function bar() { var x = 1; var y = 2; return (x*y)|0; }\n"
658       "function foo() { bar(); }",
659       "asm: line 39: direct integer multiply forbidden\n");
660 }
661
662
663 TEST(Division4) {
664   CHECK_FUNC_ERROR(
665       "function bar() { var x = 1; var y = 2; return (x/y/x/y)|0; }\n"
666       "function foo() { bar(); }",
667       "asm: line 39: too many consecutive multiplicative ops\n");
668 }
669
670
671 TEST(Load1) {
672   CHECK_FUNC_TYPES_BEGIN(
673       "function bar() { var x = 1; var y = i8[x>>0]|0; }\n"
674       "function foo() { bar(); }") {
675     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
676       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
677         CHECK_VAR(x, Bounds(cache.kInt32));
678         CHECK_EXPR(Literal, Bounds(cache.kInt32));
679       }
680       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
681         CHECK_VAR(y, Bounds(cache.kInt32));
682         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
683           CHECK_EXPR(Property, Bounds(cache.kInt8)) {
684             CHECK_VAR(i8, Bounds(cache.kInt8Array));
685             CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
686               CHECK_VAR(x, Bounds(cache.kInt32));
687               CHECK_EXPR(Literal, Bounds(cache.kInt32));
688             }
689           }
690           CHECK_EXPR(Literal, Bounds(cache.kInt32));
691         }
692       }
693     }
694     CHECK_SKIP();
695   }
696   CHECK_FUNC_TYPES_END
697 }
698
699
700 TEST(FunctionTables) {
701   CHECK_FUNC_TYPES_BEGIN(
702       "function func1(x) { x = x | 0; return (x * 5) | 0; }\n"
703       "function func2(x) { x = x | 0; return (x * 25) | 0; }\n"
704       "var table1 = [func1, func2];\n"
705       "function bar(x, y) { x = x | 0; y = y | 0;\n"
706       "   return table1[x & 1](y)|0; }\n"
707       "function foo() { bar(1, 2); }") {
708     CHECK_EXPR(FunctionLiteral, FUNC_I2I_TYPE) {
709       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
710         CHECK_VAR(x, Bounds(cache.kInt32));
711         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
712           CHECK_VAR(x, Bounds(cache.kInt32));
713           CHECK_EXPR(Literal, Bounds(cache.kInt32));
714         }
715       }
716       CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
717         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
718           CHECK_VAR(x, Bounds(cache.kInt32));
719           CHECK_EXPR(Literal, Bounds(cache.kInt32));
720         }
721         CHECK_EXPR(Literal, Bounds(cache.kInt32));
722       }
723     }
724     CHECK_EXPR(FunctionLiteral, FUNC_I2I_TYPE) {
725       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
726         CHECK_VAR(x, Bounds(cache.kInt32));
727         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
728           CHECK_VAR(x, Bounds(cache.kInt32));
729           CHECK_EXPR(Literal, Bounds(cache.kInt32));
730         }
731       }
732       CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
733         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
734           CHECK_VAR(x, Bounds(cache.kInt32));
735           CHECK_EXPR(Literal, Bounds(cache.kInt32));
736         }
737         CHECK_EXPR(Literal, Bounds(cache.kInt32));
738       }
739     }
740     CHECK_EXPR(FunctionLiteral, FUNC_II2I_TYPE) {
741       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
742         CHECK_VAR(x, Bounds(cache.kInt32));
743         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
744           CHECK_VAR(x, Bounds(cache.kInt32));
745           CHECK_EXPR(Literal, Bounds(cache.kInt32));
746         }
747       }
748       CHECK_EXPR(Assignment, Bounds(cache.kInt32)) {
749         CHECK_VAR(y, Bounds(cache.kInt32));
750         CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
751           CHECK_VAR(y, Bounds(cache.kInt32));
752           CHECK_EXPR(Literal, Bounds(cache.kInt32));
753         }
754       }
755       CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
756         CHECK_EXPR(Call, Bounds(cache.kInt32)) {
757           CHECK_EXPR(Property, FUNC_I2I_TYPE) {
758             CHECK_VAR(table1, FUNC_I2I_ARRAY_TYPE);
759             CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
760               CHECK_VAR(x, Bounds(cache.kInt32));
761               CHECK_EXPR(Literal, Bounds(cache.kInt32));
762             }
763           }
764           CHECK_VAR(y, Bounds(cache.kInt32));
765         }
766         CHECK_EXPR(Literal, Bounds(cache.kInt32));
767       }
768     }
769     CHECK_SKIP();
770   }
771   CHECK_FUNC_TYPES_END_1();
772   CHECK_EXPR(Assignment, FUNC_I2I_ARRAY_TYPE) {
773     CHECK_VAR(table1, FUNC_I2I_ARRAY_TYPE);
774     CHECK_EXPR(ArrayLiteral, FUNC_I2I_ARRAY_TYPE) {
775       CHECK_VAR(func1, FUNC_I2I_TYPE);
776       CHECK_VAR(func2, FUNC_I2I_TYPE);
777     }
778   }
779   CHECK_FUNC_TYPES_END_2();
780 }
781
782
783 TEST(BadFunctionTable) {
784   CHECK_FUNC_ERROR(
785       "function func1(x) { x = x | 0; return (x * 5) | 0; }\n"
786       "var table1 = [func1, 1];\n"
787       "function bar(x, y) { x = x | 0; y = y | 0;\n"
788       "   return table1[x & 1](y)|0; }\n"
789       "function foo() { bar(1, 2); }",
790       "asm: line 40: array component expected to be a function\n");
791 }
792
793
794 TEST(MissingParameterTypes) {
795   CHECK_FUNC_ERROR(
796       "function bar(x) { var y = 1; }\n"
797       "function foo() { bar(2); }",
798       "asm: line 39: missing parameter type annotations\n");
799 }
800
801
802 TEST(InvalidTypeAnnotationBinaryOpDiv) {
803   CHECK_FUNC_ERROR(
804       "function bar(x) { x = x / 4; }\n"
805       "function foo() { bar(2); }",
806       "asm: line 39: invalid type annotation on binary op\n");
807 }
808
809
810 TEST(InvalidTypeAnnotationBinaryOpMul) {
811   CHECK_FUNC_ERROR(
812       "function bar(x) { x = x * 4.0; }\n"
813       "function foo() { bar(2); }",
814       "asm: line 39: invalid type annotation on binary op\n");
815 }
816
817
818 TEST(InvalidArgumentCount) {
819   CHECK_FUNC_ERROR(
820       "function bar(x) { return fround(4, 5); }\n"
821       "function foo() { bar(); }",
822       "asm: line 39: invalid argument count calling fround\n");
823 }
824
825
826 TEST(InvalidTypeAnnotationArity) {
827   CHECK_FUNC_ERROR(
828       "function bar(x) { x = max(x); }\n"
829       "function foo() { bar(3); }",
830       "asm: line 39: only fround allowed on expression annotations\n");
831 }
832
833
834 TEST(InvalidTypeAnnotationOnlyFround) {
835   CHECK_FUNC_ERROR(
836       "function bar(x) { x = sin(x); }\n"
837       "function foo() { bar(3); }",
838       "asm: line 39: only fround allowed on expression annotations\n");
839 }
840
841
842 TEST(InvalidTypeAnnotation) {
843   CHECK_FUNC_ERROR(
844       "function bar(x) { x = (x+x)(x); }\n"
845       "function foo() { bar(3); }",
846       "asm: line 39: invalid type annotation\n");
847 }
848
849
850 TEST(WithStatement) {
851   CHECK_FUNC_ERROR(
852       "function bar() { var x = 0; with (x) { x = x + 1; } }\n"
853       "function foo() { bar(); }",
854       "asm: line 39: bad with statement\n");
855 }
856
857
858 TEST(NestedFunction) {
859   CHECK_FUNC_ERROR(
860       "function bar() { function x() { return 1; } }\n"
861       "function foo() { bar(); }",
862       "asm: line 39: function declared inside another\n");
863 }
864
865
866 TEST(UnboundVariable) {
867   CHECK_FUNC_ERROR(
868       "function bar() { var x = y; }\n"
869       "function foo() { bar(); }",
870       "asm: line 39: unbound variable\n");
871 }
872
873
874 TEST(ForeignFunction) {
875   CHECK_FUNC_TYPES_BEGIN(
876       "var baz = foreign.baz;\n"
877       "function bar() { return baz(1, 2)|0; }\n"
878       "function foo() { bar(); }") {
879     CHECK_EXPR(FunctionLiteral, FUNC_I_TYPE) {
880       CHECK_EXPR(BinaryOperation, Bounds(cache.kInt32)) {
881         CHECK_EXPR(Call, Bounds(Type::Number(zone))) {
882           CHECK_VAR(baz, Bounds(Type::Any()));
883           CHECK_EXPR(Literal, Bounds(cache.kInt32));
884           CHECK_EXPR(Literal, Bounds(cache.kInt32));
885         }
886         CHECK_EXPR(Literal, Bounds(cache.kInt32));
887       }
888     }
889     CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) {
890       CHECK_EXPR(Call, Bounds(cache.kInt32)) { CHECK_VAR(bar, FUNC_I_TYPE); }
891     }
892   }
893   CHECK_FUNC_TYPES_END_1()
894   CHECK_EXPR(Assignment, Bounds(Type::Any())) {
895     CHECK_VAR(baz, Bounds(Type::Any()));
896     CHECK_EXPR(Property, Bounds(Type::Any())) {
897       CHECK_VAR(foreign, Bounds::Unbounded());
898       CHECK_EXPR(Literal, Bounds::Unbounded());
899     }
900   }
901   CHECK_FUNC_TYPES_END_2()
902 }
903
904
905 TEST(BadExports) {
906   HARNESS_PREAMBLE()
907   "function foo() {};\n"
908   "return {foo: foo, bar: 1};"
909   "}\n";
910
911   v8::V8::Initialize();
912   HandleAndZoneScope handles;
913   Zone* zone = handles.main_zone();
914   ZoneVector<ExpressionTypeEntry> types(zone);
915   CHECK_EQ("asm: line 40: non-function in function table\n",
916            Validate(zone, test_function, &types));
917 }