OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/asmjs/asm-typer.h" | 5 #include "src/asmjs/asm-typer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <memory> | 9 #include <memory> |
10 #include <string> | 10 #include <string> |
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 DCHECK_NE(type, AsmType::None()); | 444 DCHECK_NE(type, AsmType::None()); |
445 if (in_function_) { | 445 if (in_function_) { |
446 DCHECK(function_node_types_.find(node) == function_node_types_.end()); | 446 DCHECK(function_node_types_.find(node) == function_node_types_.end()); |
447 function_node_types_.insert(std::make_pair(node, type)); | 447 function_node_types_.insert(std::make_pair(node, type)); |
448 } else { | 448 } else { |
449 DCHECK(module_node_types_.find(node) == module_node_types_.end()); | 449 DCHECK(module_node_types_.find(node) == module_node_types_.end()); |
450 module_node_types_.insert(std::make_pair(node, type)); | 450 module_node_types_.insert(std::make_pair(node, type)); |
451 } | 451 } |
452 } | 452 } |
453 | 453 |
| 454 namespace { |
| 455 bool IsLiteralDouble(Literal* literal) { |
| 456 return literal->raw_value()->IsNumber() && |
| 457 literal->raw_value()->ContainsDot(); |
| 458 } |
| 459 |
| 460 bool IsLiteralInt(Literal* literal) { |
| 461 return literal->raw_value()->IsNumber() && |
| 462 !literal->raw_value()->ContainsDot(); |
| 463 } |
| 464 |
| 465 bool IsLiteralMinus1(Literal* literal) { |
| 466 return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == -1.0; |
| 467 } |
| 468 |
| 469 bool IsLiteral1Dot0(Literal* literal) { |
| 470 return IsLiteralDouble(literal) && literal->raw_value()->AsNumber() == 1.0; |
| 471 } |
| 472 |
| 473 bool IsLiteral0(Literal* literal) { |
| 474 return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == 0.0; |
| 475 } |
| 476 } // namespace |
| 477 |
454 AsmType* AsmTyper::TypeOf(AstNode* node) const { | 478 AsmType* AsmTyper::TypeOf(AstNode* node) const { |
455 auto node_type_iter = function_node_types_.find(node); | 479 auto node_type_iter = function_node_types_.find(node); |
456 if (node_type_iter != function_node_types_.end()) { | 480 if (node_type_iter != function_node_types_.end()) { |
457 return node_type_iter->second; | 481 return node_type_iter->second; |
458 } | 482 } |
459 node_type_iter = module_node_types_.find(node); | 483 node_type_iter = module_node_types_.find(node); |
460 if (node_type_iter != module_node_types_.end()) { | 484 if (node_type_iter != module_node_types_.end()) { |
461 return node_type_iter->second; | 485 return node_type_iter->second; |
462 } | 486 } |
463 | 487 |
464 // Sometimes literal nodes are not added to the node_type_ map simply because | 488 // Sometimes literal nodes are not added to the node_type_ map simply because |
465 // their are not visited with ValidateExpression(). | 489 // their are not visited with ValidateExpression(). |
466 if (auto* literal = node->AsLiteral()) { | 490 if (auto* literal = node->AsLiteral()) { |
467 if (literal->raw_value()->ContainsDot()) { | 491 if (IsLiteralDouble(literal)) { |
468 return AsmType::Double(); | 492 return AsmType::Double(); |
469 } | 493 } |
| 494 if (!IsLiteralInt(literal)) { |
| 495 return AsmType::None(); |
| 496 } |
470 uint32_t u; | 497 uint32_t u; |
471 if (literal->value()->ToUint32(&u)) { | 498 if (literal->value()->ToUint32(&u)) { |
472 if (u > LargestFixNum) { | 499 if (u > LargestFixNum) { |
473 return AsmType::Unsigned(); | 500 return AsmType::Unsigned(); |
474 } | 501 } |
475 return AsmType::FixNum(); | 502 return AsmType::FixNum(); |
476 } | 503 } |
477 int32_t i; | 504 int32_t i; |
478 if (literal->value()->ToInt32(&i)) { | 505 if (literal->value()->ToInt32(&i)) { |
479 return AsmType::Signed(); | 506 return AsmType::Signed(); |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 // *VIOLATION* The parser replaces uses of +x with x*1.0. | 754 // *VIOLATION* The parser replaces uses of +x with x*1.0. |
728 if (binop->op() != Token::MUL) { | 755 if (binop->op() != Token::MUL) { |
729 return false; | 756 return false; |
730 } | 757 } |
731 | 758 |
732 auto* right_as_literal = binop->right()->AsLiteral(); | 759 auto* right_as_literal = binop->right()->AsLiteral(); |
733 if (right_as_literal == nullptr) { | 760 if (right_as_literal == nullptr) { |
734 return false; | 761 return false; |
735 } | 762 } |
736 | 763 |
737 return right_as_literal->raw_value()->ContainsDot() && | 764 return IsLiteral1Dot0(right_as_literal); |
738 right_as_literal->raw_value()->AsNumber() == 1.0; | |
739 } | 765 } |
740 | 766 |
741 bool IsIntAnnotation(BinaryOperation* binop) { | 767 bool IsIntAnnotation(BinaryOperation* binop) { |
742 if (binop->op() != Token::BIT_OR) { | 768 if (binop->op() != Token::BIT_OR) { |
743 return false; | 769 return false; |
744 } | 770 } |
745 | 771 |
746 auto* right_as_literal = binop->right()->AsLiteral(); | 772 auto* right_as_literal = binop->right()->AsLiteral(); |
747 if (right_as_literal == nullptr) { | 773 if (right_as_literal == nullptr) { |
748 return false; | 774 return false; |
749 } | 775 } |
750 | 776 |
751 return !right_as_literal->raw_value()->ContainsDot() && | 777 return IsLiteral0(right_as_literal); |
752 right_as_literal->raw_value()->AsNumber() == 0.0; | |
753 } | 778 } |
754 } // namespace | 779 } // namespace |
755 | 780 |
756 AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) { | 781 AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) { |
757 DCHECK(!assign->is_compound()); | 782 DCHECK(!assign->is_compound()); |
758 if (assign->is_compound()) { | 783 if (assign->is_compound()) { |
759 FAIL(assign, | 784 FAIL(assign, |
760 "Compound assignment not supported when declaring global variables."); | 785 "Compound assignment not supported when declaring global variables."); |
761 } | 786 } |
762 | 787 |
(...skipping 696 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1459 | 1484 |
1460 // 6.6 ValidateCase | 1485 // 6.6 ValidateCase |
1461 namespace { | 1486 namespace { |
1462 bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) { | 1487 bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) { |
1463 auto* lbl_expr = clause->label()->AsLiteral(); | 1488 auto* lbl_expr = clause->label()->AsLiteral(); |
1464 | 1489 |
1465 if (lbl_expr == nullptr) { | 1490 if (lbl_expr == nullptr) { |
1466 return false; | 1491 return false; |
1467 } | 1492 } |
1468 | 1493 |
1469 if (lbl_expr->raw_value()->ContainsDot()) { | 1494 if (!IsLiteralInt(lbl_expr)) { |
1470 return false; | 1495 return false; |
1471 } | 1496 } |
1472 | 1497 |
1473 return lbl_expr->value()->ToInt32(lbl); | 1498 return lbl_expr->value()->ToInt32(lbl); |
1474 } | 1499 } |
1475 } // namespace | 1500 } // namespace |
1476 | 1501 |
1477 AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) { | 1502 AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) { |
1478 if (!ExtractInt32CaseLabel(label, case_lbl)) { | 1503 if (!ExtractInt32CaseLabel(label, case_lbl)) { |
1479 FAIL(label, "Case label must be a 32-bit signed integer."); | 1504 FAIL(label, "Case label must be a 32-bit signed integer."); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1556 bool IsInvert(BinaryOperation* binop) { | 1581 bool IsInvert(BinaryOperation* binop) { |
1557 if (binop->op() != Token::BIT_XOR) { | 1582 if (binop->op() != Token::BIT_XOR) { |
1558 return false; | 1583 return false; |
1559 } | 1584 } |
1560 | 1585 |
1561 auto* right_as_literal = binop->right()->AsLiteral(); | 1586 auto* right_as_literal = binop->right()->AsLiteral(); |
1562 if (right_as_literal == nullptr) { | 1587 if (right_as_literal == nullptr) { |
1563 return false; | 1588 return false; |
1564 } | 1589 } |
1565 | 1590 |
1566 return !right_as_literal->raw_value()->ContainsDot() && | 1591 return IsLiteralMinus1(right_as_literal); |
1567 right_as_literal->raw_value()->AsNumber() == -1.0; | |
1568 } | 1592 } |
1569 | 1593 |
1570 bool IsUnaryMinus(BinaryOperation* binop) { | 1594 bool IsUnaryMinus(BinaryOperation* binop) { |
1571 // *VIOLATION* The parser replaces uses of -x with x*-1. | 1595 // *VIOLATION* The parser replaces uses of -x with x*-1. |
1572 if (binop->op() != Token::MUL) { | 1596 if (binop->op() != Token::MUL) { |
1573 return false; | 1597 return false; |
1574 } | 1598 } |
1575 | 1599 |
1576 auto* right_as_literal = binop->right()->AsLiteral(); | 1600 auto* right_as_literal = binop->right()->AsLiteral(); |
1577 if (right_as_literal == nullptr) { | 1601 if (right_as_literal == nullptr) { |
1578 return false; | 1602 return false; |
1579 } | 1603 } |
1580 | 1604 |
1581 return !right_as_literal->raw_value()->ContainsDot() && | 1605 return IsLiteralMinus1(right_as_literal); |
1582 right_as_literal->raw_value()->AsNumber() == -1.0; | |
1583 } | 1606 } |
1584 } // namespace | 1607 } // namespace |
1585 | 1608 |
1586 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { | 1609 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { |
1587 #define UNOP_OVERLOAD(Src, Dest) \ | 1610 #define UNOP_OVERLOAD(Src, Dest) \ |
1588 do { \ | 1611 do { \ |
1589 if (left_type->IsA(AsmType::Src())) { \ | 1612 if (left_type->IsA(AsmType::Src())) { \ |
1590 return AsmType::Dest(); \ | 1613 return AsmType::Dest(); \ |
1591 } \ | 1614 } \ |
1592 } while (0) | 1615 } while (0) |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1701 } | 1724 } |
1702 | 1725 |
1703 // 6.8.2 NumericLiteral | 1726 // 6.8.2 NumericLiteral |
1704 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { | 1727 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { |
1705 // *VIOLATION* asm.js does not allow the use of undefined, but our parser | 1728 // *VIOLATION* asm.js does not allow the use of undefined, but our parser |
1706 // inserts them, so we have to handle them. | 1729 // inserts them, so we have to handle them. |
1707 if (literal->IsUndefinedLiteral()) { | 1730 if (literal->IsUndefinedLiteral()) { |
1708 return AsmType::Void(); | 1731 return AsmType::Void(); |
1709 } | 1732 } |
1710 | 1733 |
1711 if (literal->raw_value()->ContainsDot()) { | 1734 if (IsLiteralDouble(literal)) { |
1712 return AsmType::Double(); | 1735 return AsmType::Double(); |
1713 } | 1736 } |
1714 | 1737 |
1715 // The parser collapses expressions like !0 and !123 to true/false. | 1738 // The parser collapses expressions like !0 and !123 to true/false. |
1716 // We therefore need to permit these as alternate versions of 0 / 1. | 1739 // We therefore need to permit these as alternate versions of 0 / 1. |
1717 if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) { | 1740 if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) { |
1718 return AsmType::Int(); | 1741 return AsmType::Int(); |
1719 } | 1742 } |
1720 | 1743 |
1721 uint32_t value; | 1744 uint32_t value; |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1881 } | 1904 } |
1882 | 1905 |
1883 // 6.8.8 MultiplicativeExpression | 1906 // 6.8.8 MultiplicativeExpression |
1884 namespace { | 1907 namespace { |
1885 bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) { | 1908 bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) { |
1886 auto* literal = expr->AsLiteral(); | 1909 auto* literal = expr->AsLiteral(); |
1887 if (literal == nullptr) { | 1910 if (literal == nullptr) { |
1888 return false; | 1911 return false; |
1889 } | 1912 } |
1890 | 1913 |
1891 if (literal->raw_value()->ContainsDot()) { | 1914 if (!IsLiteralInt(literal)) { |
1892 return false; | 1915 return false; |
1893 } | 1916 } |
1894 | 1917 |
1895 if (!literal->value()->ToInt32(factor)) { | 1918 if (!literal->value()->ToInt32(factor)) { |
1896 return false; | 1919 return false; |
1897 } | 1920 } |
1898 static const int32_t kIntishBound = 1 << 20; | 1921 static const int32_t kIntishBound = 1 << 20; |
1899 return -kIntishBound < *factor && *factor < kIntishBound; | 1922 return -kIntishBound < *factor && *factor < kIntishBound; |
1900 } | 1923 } |
1901 } // namespace | 1924 } // namespace |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2290 } | 2313 } |
2291 | 2314 |
2292 // 6.9 ValidateCall | 2315 // 6.9 ValidateCall |
2293 namespace { | 2316 namespace { |
2294 bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) { | 2317 bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) { |
2295 auto* as_literal = expr->AsLiteral(); | 2318 auto* as_literal = expr->AsLiteral(); |
2296 if (as_literal == nullptr) { | 2319 if (as_literal == nullptr) { |
2297 return false; | 2320 return false; |
2298 } | 2321 } |
2299 | 2322 |
2300 if (as_literal->raw_value()->ContainsDot()) { | 2323 if (!IsLiteralInt(as_literal)) { |
2301 return false; | 2324 return false; |
2302 } | 2325 } |
2303 | 2326 |
2304 if (!as_literal->value()->ToUint32(value)) { | 2327 if (!as_literal->value()->ToUint32(value)) { |
2305 return false; | 2328 return false; |
2306 } | 2329 } |
2307 | 2330 |
2308 return base::bits::IsPowerOfTwo32(1 + *value); | 2331 return base::bits::IsPowerOfTwo32(1 + *value); |
2309 } | 2332 } |
2310 } // namespace | 2333 } // namespace |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2474 } | 2497 } |
2475 | 2498 |
2476 // 6.10 ValidateHeapAccess | 2499 // 6.10 ValidateHeapAccess |
2477 namespace { | 2500 namespace { |
2478 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) { | 2501 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) { |
2479 auto* as_literal = expr->AsLiteral(); | 2502 auto* as_literal = expr->AsLiteral(); |
2480 if (as_literal == nullptr) { | 2503 if (as_literal == nullptr) { |
2481 return false; | 2504 return false; |
2482 } | 2505 } |
2483 | 2506 |
2484 if (as_literal->raw_value()->ContainsDot()) { | 2507 if (!IsLiteralInt(as_literal)) { |
2485 return false; | 2508 return false; |
2486 } | 2509 } |
2487 | 2510 |
2488 return as_literal->value()->ToUint32(value); | 2511 return as_literal->value()->ToUint32(value); |
2489 } | 2512 } |
2490 | 2513 |
2491 // Returns whether index is too large to access a heap with the given type. | 2514 // Returns whether index is too large to access a heap with the given type. |
2492 bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) { | 2515 bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) { |
2493 switch (obj_type->ElementSizeInBytes()) { | 2516 switch (obj_type->ElementSizeInBytes()) { |
2494 case 1: | 2517 case 1: |
(...skipping 23 matching lines...) Expand all Loading... |
2518 FAIL(heap, "Undeclared identifier in heap access."); | 2541 FAIL(heap, "Undeclared identifier in heap access."); |
2519 } | 2542 } |
2520 | 2543 |
2521 auto* obj_type = obj_info->type(); | 2544 auto* obj_type = obj_info->type(); |
2522 if (!obj_type->IsA(AsmType::Heap())) { | 2545 if (!obj_type->IsA(AsmType::Heap())) { |
2523 FAIL(heap, "Identifier does not represent a heap view."); | 2546 FAIL(heap, "Identifier does not represent a heap view."); |
2524 } | 2547 } |
2525 SetTypeOf(obj, obj_type); | 2548 SetTypeOf(obj, obj_type); |
2526 | 2549 |
2527 if (auto* key_as_literal = heap->key()->AsLiteral()) { | 2550 if (auto* key_as_literal = heap->key()->AsLiteral()) { |
2528 if (key_as_literal->raw_value()->ContainsDot()) { | 2551 if (!IsLiteralInt(key_as_literal)) { |
2529 FAIL(key_as_literal, "Heap access index must be int."); | 2552 FAIL(key_as_literal, "Heap access index must be int."); |
2530 } | 2553 } |
2531 | 2554 |
2532 uint32_t index; | 2555 uint32_t index; |
2533 if (!key_as_literal->value()->ToUint32(&index)) { | 2556 if (!key_as_literal->value()->ToUint32(&index)) { |
2534 FAIL(key_as_literal, | 2557 FAIL(key_as_literal, |
2535 "Heap access index must be a 32-bit unsigned integer."); | 2558 "Heap access index must be a 32-bit unsigned integer."); |
2536 } | 2559 } |
2537 | 2560 |
2538 if (LiteralIndexOutOfBounds(obj_type, index)) { | 2561 if (LiteralIndexOutOfBounds(obj_type, index)) { |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2702 | 2725 |
2703 if (auto* call = ret_expr->AsCall()) { | 2726 if (auto* call = ret_expr->AsCall()) { |
2704 if (IsCallToFround(call)) { | 2727 if (IsCallToFround(call)) { |
2705 return AsmType::Float(); | 2728 return AsmType::Float(); |
2706 } | 2729 } |
2707 FAIL(statement, "Invalid function call in return statement."); | 2730 FAIL(statement, "Invalid function call in return statement."); |
2708 } | 2731 } |
2709 | 2732 |
2710 if (auto* literal = ret_expr->AsLiteral()) { | 2733 if (auto* literal = ret_expr->AsLiteral()) { |
2711 int32_t _; | 2734 int32_t _; |
2712 if (literal->raw_value()->ContainsDot()) { | 2735 if (IsLiteralDouble(literal)) { |
2713 return AsmType::Double(); | 2736 return AsmType::Double(); |
2714 } else if (literal->value()->ToInt32(&_)) { | 2737 } else if (IsLiteralInt(literal) && literal->value()->ToInt32(&_)) { |
2715 return AsmType::Signed(); | 2738 return AsmType::Signed(); |
2716 } else if (literal->IsUndefinedLiteral()) { | 2739 } else if (literal->IsUndefinedLiteral()) { |
2717 // *VIOLATION* The parser changes | 2740 // *VIOLATION* The parser changes |
2718 // | 2741 // |
2719 // return; | 2742 // return; |
2720 // | 2743 // |
2721 // into | 2744 // into |
2722 // | 2745 // |
2723 // return undefined | 2746 // return undefined |
2724 return AsmType::Void(); | 2747 return AsmType::Void(); |
(...skipping 20 matching lines...) Expand all Loading... |
2745 } | 2768 } |
2746 | 2769 |
2747 FAIL(statement, "Invalid return type expression."); | 2770 FAIL(statement, "Invalid return type expression."); |
2748 } | 2771 } |
2749 | 2772 |
2750 // 5.4 VariableTypeAnnotations | 2773 // 5.4 VariableTypeAnnotations |
2751 // Also used for 5.5 GlobalVariableTypeAnnotations | 2774 // Also used for 5.5 GlobalVariableTypeAnnotations |
2752 AsmType* AsmTyper::VariableTypeAnnotations( | 2775 AsmType* AsmTyper::VariableTypeAnnotations( |
2753 Expression* initializer, VariableInfo::Mutability mutability_type) { | 2776 Expression* initializer, VariableInfo::Mutability mutability_type) { |
2754 if (auto* literal = initializer->AsLiteral()) { | 2777 if (auto* literal = initializer->AsLiteral()) { |
2755 if (literal->raw_value()->ContainsDot()) { | 2778 if (IsLiteralDouble(literal)) { |
2756 SetTypeOf(initializer, AsmType::Double()); | 2779 SetTypeOf(initializer, AsmType::Double()); |
2757 return AsmType::Double(); | 2780 return AsmType::Double(); |
2758 } | 2781 } |
| 2782 if (!IsLiteralInt(literal)) { |
| 2783 FAIL(initializer, "Invalid type annotation - forbidden literal."); |
| 2784 } |
2759 int32_t i32; | 2785 int32_t i32; |
2760 uint32_t u32; | 2786 uint32_t u32; |
2761 | |
2762 AsmType* initializer_type = nullptr; | 2787 AsmType* initializer_type = nullptr; |
2763 if (literal->value()->ToUint32(&u32)) { | 2788 if (literal->value()->ToUint32(&u32)) { |
2764 if (u32 > LargestFixNum) { | 2789 if (u32 > LargestFixNum) { |
2765 initializer_type = AsmType::Unsigned(); | 2790 initializer_type = AsmType::Unsigned(); |
2766 SetTypeOf(initializer, initializer_type); | 2791 SetTypeOf(initializer, initializer_type); |
2767 } else { | 2792 } else { |
2768 initializer_type = AsmType::FixNum(); | 2793 initializer_type = AsmType::FixNum(); |
2769 SetTypeOf(initializer, initializer_type); | 2794 SetTypeOf(initializer, initializer_type); |
2770 initializer_type = AsmType::Signed(); | 2795 initializer_type = AsmType::Signed(); |
2771 } | 2796 } |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2879 return true; | 2904 return true; |
2880 } | 2905 } |
2881 | 2906 |
2882 *error_message = typer.error_message(); | 2907 *error_message = typer.error_message(); |
2883 return false; | 2908 return false; |
2884 } | 2909 } |
2885 | 2910 |
2886 } // namespace wasm | 2911 } // namespace wasm |
2887 } // namespace internal | 2912 } // namespace internal |
2888 } // namespace v8 | 2913 } // namespace v8 |
OLD | NEW |