OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/typing-asm.h" | 5 #include "src/typing-asm.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 | 10 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 #undef V | 55 #undef V |
56 global_variable_type_(HashMap::PointersMatch, | 56 global_variable_type_(HashMap::PointersMatch, |
57 ZoneHashMap::kDefaultHashMapCapacity, | 57 ZoneHashMap::kDefaultHashMapCapacity, |
58 ZoneAllocationPolicy(zone)), | 58 ZoneAllocationPolicy(zone)), |
59 local_variable_type_(HashMap::PointersMatch, | 59 local_variable_type_(HashMap::PointersMatch, |
60 ZoneHashMap::kDefaultHashMapCapacity, | 60 ZoneHashMap::kDefaultHashMapCapacity, |
61 ZoneAllocationPolicy(zone)), | 61 ZoneAllocationPolicy(zone)), |
62 in_function_(false), | 62 in_function_(false), |
63 building_function_tables_(false), | 63 building_function_tables_(false), |
64 visiting_exports_(false), | 64 visiting_exports_(false), |
65 cache_(TypeCache::Get()) { | 65 cache_(TypeCache::Get()), |
| 66 bounds_(zone) { |
66 InitializeAstVisitor(isolate); | 67 InitializeAstVisitor(isolate); |
67 InitializeStdlib(); | 68 InitializeStdlib(); |
68 } | 69 } |
69 | 70 |
70 | 71 |
71 bool AsmTyper::Validate() { | 72 bool AsmTyper::Validate() { |
72 VisitAsmModule(root_); | 73 VisitAsmModule(root_); |
73 return valid_ && !HasStackOverflow(); | 74 return valid_ && !HasStackOverflow(); |
74 } | 75 } |
75 | 76 |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 } | 488 } |
488 | 489 |
489 | 490 |
490 void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) { | 491 void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) { |
491 if (in_function_) { | 492 if (in_function_) { |
492 FAIL(expr, "invalid nested function"); | 493 FAIL(expr, "invalid nested function"); |
493 } | 494 } |
494 Scope* scope = expr->scope(); | 495 Scope* scope = expr->scope(); |
495 DCHECK(scope->is_function_scope()); | 496 DCHECK(scope->is_function_scope()); |
496 | 497 |
497 if (!expr->bounds().upper->IsFunction()) { | 498 if (!bounds_.get(expr).upper->IsFunction()) { |
498 FAIL(expr, "invalid function literal"); | 499 FAIL(expr, "invalid function literal"); |
499 } | 500 } |
500 | 501 |
501 Type* type = expr->bounds().upper; | 502 Type* type = bounds_.get(expr).upper; |
502 Type* save_return_type = return_type_; | 503 Type* save_return_type = return_type_; |
503 return_type_ = type->AsFunction()->Result(); | 504 return_type_ = type->AsFunction()->Result(); |
504 in_function_ = true; | 505 in_function_ = true; |
505 local_variable_type_.Clear(); | 506 local_variable_type_.Clear(); |
506 RECURSE(VisitDeclarations(scope->declarations())); | 507 RECURSE(VisitDeclarations(scope->declarations())); |
507 RECURSE(VisitStatements(expr->body())); | 508 RECURSE(VisitStatements(expr->body())); |
508 in_function_ = false; | 509 in_function_ = false; |
509 return_type_ = save_return_type; | 510 return_type_ = save_return_type; |
510 IntersectResult(expr, type); | 511 IntersectResult(expr, type); |
511 } | 512 } |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 if (right == nullptr || right->raw_value()->ContainsDot()) { | 797 if (right == nullptr || right->raw_value()->ContainsDot()) { |
797 FAIL(bin->right(), "heap access shift must be integer"); | 798 FAIL(bin->right(), "heap access shift must be integer"); |
798 } | 799 } |
799 RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, | 800 RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, |
800 "array shift expected to be integer")); | 801 "array shift expected to be integer")); |
801 int n = static_cast<int>(right->raw_value()->AsNumber()); | 802 int n = static_cast<int>(right->raw_value()->AsNumber()); |
802 if (expected_shift < 0 || n != expected_shift) { | 803 if (expected_shift < 0 || n != expected_shift) { |
803 FAIL(right, "heap access shift must match element size"); | 804 FAIL(right, "heap access shift must match element size"); |
804 } | 805 } |
805 } | 806 } |
806 expr->key()->set_bounds(Bounds(cache_.kAsmSigned)); | 807 bounds_.set(expr->key(), Bounds(cache_.kAsmSigned)); |
807 } | 808 } |
808 Type* result_type; | 809 Type* result_type; |
809 if (type->Is(cache_.kAsmIntArrayElement)) { | 810 if (type->Is(cache_.kAsmIntArrayElement)) { |
810 result_type = cache_.kAsmIntQ; | 811 result_type = cache_.kAsmIntQ; |
811 intish_ = kMaxUncombinedAdditiveSteps; | 812 intish_ = kMaxUncombinedAdditiveSteps; |
812 } else if (type->Is(cache_.kAsmFloat)) { | 813 } else if (type->Is(cache_.kAsmFloat)) { |
813 if (assigning) { | 814 if (assigning) { |
814 result_type = cache_.kAsmFloatDoubleQ; | 815 result_type = cache_.kAsmFloatDoubleQ; |
815 } else { | 816 } else { |
816 result_type = cache_.kAsmFloatQ; | 817 result_type = cache_.kAsmFloatQ; |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
947 FAIL(expr, "invalid property access"); | 948 FAIL(expr, "invalid property access"); |
948 } | 949 } |
949 | 950 |
950 void AsmTyper::CheckPolymorphicStdlibArguments( | 951 void AsmTyper::CheckPolymorphicStdlibArguments( |
951 enum StandardMember standard_member, ZoneList<Expression*>* args) { | 952 enum StandardMember standard_member, ZoneList<Expression*>* args) { |
952 if (args->length() == 0) { | 953 if (args->length() == 0) { |
953 return; | 954 return; |
954 } | 955 } |
955 // Handle polymorphic stdlib functions specially. | 956 // Handle polymorphic stdlib functions specially. |
956 Expression* arg0 = args->at(0); | 957 Expression* arg0 = args->at(0); |
957 Type* arg0_type = arg0->bounds().upper; | 958 Type* arg0_type = bounds_.get(arg0).upper; |
958 switch (standard_member) { | 959 switch (standard_member) { |
959 case kMathFround: { | 960 case kMathFround: { |
960 if (!arg0_type->Is(cache_.kAsmFloat) && | 961 if (!arg0_type->Is(cache_.kAsmFloat) && |
961 !arg0_type->Is(cache_.kAsmDouble) && | 962 !arg0_type->Is(cache_.kAsmDouble) && |
962 !arg0_type->Is(cache_.kAsmSigned) && | 963 !arg0_type->Is(cache_.kAsmSigned) && |
963 !arg0_type->Is(cache_.kAsmUnsigned)) { | 964 !arg0_type->Is(cache_.kAsmUnsigned)) { |
964 FAIL(arg0, "illegal function argument type"); | 965 FAIL(arg0, "illegal function argument type"); |
965 } | 966 } |
966 break; | 967 break; |
967 } | 968 } |
968 case kMathCeil: | 969 case kMathCeil: |
969 case kMathFloor: | 970 case kMathFloor: |
970 case kMathSqrt: { | 971 case kMathSqrt: { |
971 if (!arg0_type->Is(cache_.kAsmFloat) && | 972 if (!arg0_type->Is(cache_.kAsmFloat) && |
972 !arg0_type->Is(cache_.kAsmDouble)) { | 973 !arg0_type->Is(cache_.kAsmDouble)) { |
973 FAIL(arg0, "illegal function argument type"); | 974 FAIL(arg0, "illegal function argument type"); |
974 } | 975 } |
975 break; | 976 break; |
976 } | 977 } |
977 case kMathAbs: | 978 case kMathAbs: |
978 case kMathMin: | 979 case kMathMin: |
979 case kMathMax: { | 980 case kMathMax: { |
980 if (!arg0_type->Is(cache_.kAsmFloat) && | 981 if (!arg0_type->Is(cache_.kAsmFloat) && |
981 !arg0_type->Is(cache_.kAsmDouble) && | 982 !arg0_type->Is(cache_.kAsmDouble) && |
982 !arg0_type->Is(cache_.kAsmSigned)) { | 983 !arg0_type->Is(cache_.kAsmSigned)) { |
983 FAIL(arg0, "illegal function argument type"); | 984 FAIL(arg0, "illegal function argument type"); |
984 } | 985 } |
985 if (args->length() > 1) { | 986 if (args->length() > 1) { |
986 Type* other = Type::Intersect(args->at(0)->bounds().upper, | 987 Type* other = Type::Intersect(bounds_.get(args->at(0)).upper, |
987 args->at(1)->bounds().upper, zone()); | 988 bounds_.get(args->at(1)).upper, zone()); |
988 if (!other->Is(cache_.kAsmFloat) && !other->Is(cache_.kAsmDouble) && | 989 if (!other->Is(cache_.kAsmFloat) && !other->Is(cache_.kAsmDouble) && |
989 !other->Is(cache_.kAsmSigned)) { | 990 !other->Is(cache_.kAsmSigned)) { |
990 FAIL(arg0, "function arguments types don't match"); | 991 FAIL(arg0, "function arguments types don't match"); |
991 } | 992 } |
992 } | 993 } |
993 break; | 994 break; |
994 } | 995 } |
995 default: { break; } | 996 default: { break; } |
996 } | 997 } |
997 } | 998 } |
(...skipping 26 matching lines...) Expand all Loading... |
1024 // Checking for asm extern types explicitly, as the type system | 1025 // Checking for asm extern types explicitly, as the type system |
1025 // doesn't correctly check their inheritance relationship. | 1026 // doesn't correctly check their inheritance relationship. |
1026 if (!computed_type_->Is(cache_.kAsmSigned) && | 1027 if (!computed_type_->Is(cache_.kAsmSigned) && |
1027 !computed_type_->Is(cache_.kAsmFixnum) && | 1028 !computed_type_->Is(cache_.kAsmFixnum) && |
1028 !computed_type_->Is(cache_.kAsmDouble)) { | 1029 !computed_type_->Is(cache_.kAsmDouble)) { |
1029 FAIL(arg, | 1030 FAIL(arg, |
1030 "foreign call argument expected to be int, double, or fixnum"); | 1031 "foreign call argument expected to be int, double, or fixnum"); |
1031 } | 1032 } |
1032 } | 1033 } |
1033 intish_ = 0; | 1034 intish_ = 0; |
1034 expr->expression()->set_bounds( | 1035 bounds_.set(expr->expression(), |
1035 Bounds(Type::Function(Type::Any(), zone()))); | 1036 Bounds(Type::Function(Type::Any(), zone()))); |
1036 IntersectResult(expr, expected_type); | 1037 IntersectResult(expr, expected_type); |
1037 } else { | 1038 } else { |
1038 if (fun_type->Arity() != args->length()) { | 1039 if (fun_type->Arity() != args->length()) { |
1039 FAIL(expr, "call with wrong arity"); | 1040 FAIL(expr, "call with wrong arity"); |
1040 } | 1041 } |
1041 for (int i = 0; i < args->length(); ++i) { | 1042 for (int i = 0; i < args->length(); ++i) { |
1042 Expression* arg = args->at(i); | 1043 Expression* arg = args->at(i); |
1043 RECURSE(VisitWithExpectation( | 1044 RECURSE(VisitWithExpectation( |
1044 arg, fun_type->Parameter(i), | 1045 arg, fun_type->Parameter(i), |
1045 "call argument expected to match callee parameter")); | 1046 "call argument expected to match callee parameter")); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1191 return; | 1192 return; |
1192 } | 1193 } |
1193 case Token::OR: | 1194 case Token::OR: |
1194 case Token::AND: | 1195 case Token::AND: |
1195 FAIL(expr, "illegal logical operator"); | 1196 FAIL(expr, "illegal logical operator"); |
1196 case Token::BIT_OR: { | 1197 case Token::BIT_OR: { |
1197 // BIT_OR allows Any since it is used as a type coercion. | 1198 // BIT_OR allows Any since it is used as a type coercion. |
1198 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, | 1199 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, |
1199 cache_.kAsmSigned, true)); | 1200 cache_.kAsmSigned, true)); |
1200 if (expr->left()->IsCall() && expr->op() == Token::BIT_OR && | 1201 if (expr->left()->IsCall() && expr->op() == Token::BIT_OR && |
1201 Type::Number()->Is(expr->left()->bounds().upper)) { | 1202 Type::Number()->Is(bounds_.get(expr->left()).upper)) { |
1202 // Force the return types of foreign functions. | 1203 // Force the return types of foreign functions. |
1203 expr->left()->set_bounds(Bounds(cache_.kAsmSigned)); | 1204 bounds_.set(expr->left(), Bounds(cache_.kAsmSigned)); |
1204 } | 1205 } |
1205 if (in_function_ && !expr->left()->bounds().upper->Is(cache_.kAsmIntQ)) { | 1206 if (in_function_ && |
| 1207 !bounds_.get(expr->left()).upper->Is(cache_.kAsmIntQ)) { |
1206 FAIL(expr->left(), "intish required"); | 1208 FAIL(expr->left(), "intish required"); |
1207 } | 1209 } |
1208 return; | 1210 return; |
1209 } | 1211 } |
1210 case Token::BIT_XOR: { | 1212 case Token::BIT_XOR: { |
1211 // Handle booleans specially to handle de-sugared ! | 1213 // Handle booleans specially to handle de-sugared ! |
1212 Literal* left = expr->left()->AsLiteral(); | 1214 Literal* left = expr->left()->AsLiteral(); |
1213 if (left && left->value()->IsBoolean()) { | 1215 if (left && left->value()->IsBoolean()) { |
1214 if (left->ToBooleanIsTrue()) { | 1216 if (left->ToBooleanIsTrue()) { |
1215 left->set_bounds(Bounds(cache_.kSingletonOne)); | 1217 bounds_.set(left, Bounds(cache_.kSingletonOne)); |
1216 RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ, | 1218 RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ, |
1217 "not operator expects an integer")); | 1219 "not operator expects an integer")); |
1218 IntersectResult(expr, cache_.kAsmSigned); | 1220 IntersectResult(expr, cache_.kAsmSigned); |
1219 return; | 1221 return; |
1220 } else { | 1222 } else { |
1221 FAIL(left, "unexpected false"); | 1223 FAIL(left, "unexpected false"); |
1222 } | 1224 } |
1223 } | 1225 } |
1224 // BIT_XOR allows Any since it is used as a type coercion (via ~~). | 1226 // BIT_XOR allows Any since it is used as a type coercion (via ~~). |
1225 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, | 1227 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1292 } | 1294 } |
1293 IntersectResult(expr, cache_.kAsmInt); | 1295 IntersectResult(expr, cache_.kAsmInt); |
1294 return; | 1296 return; |
1295 } | 1297 } |
1296 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && | 1298 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && |
1297 right_type->Is(cache_.kAsmDouble) && | 1299 right_type->Is(cache_.kAsmDouble) && |
1298 expr->right()->AsLiteral()->raw_value()->ContainsDot() && | 1300 expr->right()->AsLiteral()->raw_value()->ContainsDot() && |
1299 expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) { | 1301 expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) { |
1300 // For unary +, expressed as x * 1.0 | 1302 // For unary +, expressed as x * 1.0 |
1301 if (expr->left()->IsCall() && | 1303 if (expr->left()->IsCall() && |
1302 Type::Number()->Is(expr->left()->bounds().upper)) { | 1304 Type::Number()->Is(bounds_.get(expr->left()).upper)) { |
1303 // Force the return types of foreign functions. | 1305 // Force the return types of foreign functions. |
1304 expr->left()->set_bounds(Bounds(cache_.kAsmDouble)); | 1306 bounds_.set(expr->left(), Bounds(cache_.kAsmDouble)); |
1305 left_type = expr->left()->bounds().upper; | 1307 left_type = bounds_.get(expr->left()).upper; |
1306 } | 1308 } |
1307 if (!(expr->left()->IsProperty() && | 1309 if (!(expr->left()->IsProperty() && |
1308 Type::Number()->Is(expr->left()->bounds().upper))) { | 1310 Type::Number()->Is(bounds_.get(expr->left()).upper))) { |
1309 if (!left_type->Is(cache_.kAsmSigned) && | 1311 if (!left_type->Is(cache_.kAsmSigned) && |
1310 !left_type->Is(cache_.kAsmUnsigned) && | 1312 !left_type->Is(cache_.kAsmUnsigned) && |
1311 !left_type->Is(cache_.kAsmFixnum) && | 1313 !left_type->Is(cache_.kAsmFixnum) && |
1312 !left_type->Is(cache_.kAsmFloatQ) && | 1314 !left_type->Is(cache_.kAsmFloatQ) && |
1313 !left_type->Is(cache_.kAsmDoubleQ)) { | 1315 !left_type->Is(cache_.kAsmDoubleQ)) { |
1314 FAIL( | 1316 FAIL( |
1315 expr->left(), | 1317 expr->left(), |
1316 "unary + only allowed on signed, unsigned, float?, or double?"); | 1318 "unary + only allowed on signed, unsigned, float?, or double?"); |
1317 } | 1319 } |
1318 } | 1320 } |
1319 IntersectResult(expr, cache_.kAsmDouble); | 1321 IntersectResult(expr, cache_.kAsmDouble); |
1320 return; | 1322 return; |
1321 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) && | 1323 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) && |
1322 expr->right()->IsLiteral() && | 1324 expr->right()->IsLiteral() && |
1323 !expr->right()->AsLiteral()->raw_value()->ContainsDot() && | 1325 !expr->right()->AsLiteral()->raw_value()->ContainsDot() && |
1324 expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) { | 1326 expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) { |
1325 // For unary -, expressed as x * -1 | 1327 // For unary -, expressed as x * -1 |
1326 expr->right()->set_bounds(Bounds(cache_.kAsmDouble)); | 1328 bounds_.set(expr->right(), Bounds(cache_.kAsmDouble)); |
1327 IntersectResult(expr, cache_.kAsmDouble); | 1329 IntersectResult(expr, cache_.kAsmDouble); |
1328 return; | 1330 return; |
1329 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { | 1331 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { |
1330 if (left_intish != 0 || right_intish != 0) { | 1332 if (left_intish != 0 || right_intish != 0) { |
1331 FAIL(expr, "float operation before required fround"); | 1333 FAIL(expr, "float operation before required fround"); |
1332 } | 1334 } |
1333 IntersectResult(expr, cache_.kAsmFloat); | 1335 IntersectResult(expr, cache_.kAsmFloat); |
1334 intish_ = 1; | 1336 intish_ = 1; |
1335 return; | 1337 return; |
1336 } else if (type->Is(cache_.kAsmDouble)) { | 1338 } else if (type->Is(cache_.kAsmDouble)) { |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1582 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember( | 1584 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember( |
1583 Variable* variable) { | 1585 Variable* variable) { |
1584 VariableInfo* info = GetVariableInfo(variable); | 1586 VariableInfo* info = GetVariableInfo(variable); |
1585 if (!info) return kNone; | 1587 if (!info) return kNone; |
1586 return info->standard_member; | 1588 return info->standard_member; |
1587 } | 1589 } |
1588 | 1590 |
1589 | 1591 |
1590 void AsmTyper::SetResult(Expression* expr, Type* type) { | 1592 void AsmTyper::SetResult(Expression* expr, Type* type) { |
1591 computed_type_ = type; | 1593 computed_type_ = type; |
1592 expr->set_bounds(Bounds(computed_type_)); | 1594 bounds_.set(expr, Bounds(computed_type_)); |
1593 } | 1595 } |
1594 | 1596 |
1595 | 1597 |
1596 void AsmTyper::IntersectResult(Expression* expr, Type* type) { | 1598 void AsmTyper::IntersectResult(Expression* expr, Type* type) { |
1597 computed_type_ = type; | 1599 computed_type_ = type; |
1598 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); | 1600 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); |
1599 expr->set_bounds(Bounds(bounded_type)); | 1601 bounds_.set(expr, Bounds(bounded_type)); |
1600 } | 1602 } |
1601 | 1603 |
1602 | 1604 |
1603 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type, | 1605 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type, |
1604 const char* msg) { | 1606 const char* msg) { |
1605 Type* save = expected_type_; | 1607 Type* save = expected_type_; |
1606 expected_type_ = expected_type; | 1608 expected_type_ = expected_type; |
1607 RECURSE(Visit(expr)); | 1609 RECURSE(Visit(expr)); |
1608 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); | 1610 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); |
1609 if (bounded_type->Is(Type::None())) { | 1611 if (bounded_type->Is(Type::None())) { |
1610 #ifdef DEBUG | 1612 #ifdef DEBUG |
1611 PrintF("Computed type: "); | 1613 PrintF("Computed type: "); |
1612 computed_type_->Print(); | 1614 computed_type_->Print(); |
1613 PrintF("Expected type: "); | 1615 PrintF("Expected type: "); |
1614 expected_type_->Print(); | 1616 expected_type_->Print(); |
1615 #endif | 1617 #endif |
1616 FAIL(expr, msg); | 1618 FAIL(expr, msg); |
1617 } | 1619 } |
1618 expected_type_ = save; | 1620 expected_type_ = save; |
1619 } | 1621 } |
1620 | 1622 |
1621 | 1623 |
1622 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) { | 1624 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) { |
1623 RECURSE(Visit(expr->expression())); | 1625 RECURSE(Visit(expr->expression())); |
1624 } | 1626 } |
1625 | 1627 |
1626 | 1628 |
1627 } // namespace internal | 1629 } // namespace internal |
1628 } // namespace v8 | 1630 } // namespace v8 |
OLD | NEW |