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