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 <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 18 using namespace v8::internal; 19 20 namespace { 21 22 static 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 51 TEST(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 273 TEST(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 300 TEST(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 317 TEST(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 342 TEST(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 363 TEST(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 399 TEST(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 } 420