OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/compiler/js-typed-lowering.h" | 5 #include "src/compiler/js-typed-lowering.h" |
6 | 6 |
7 #include "src/builtins/builtins-utils.h" | 7 #include "src/builtins/builtins-utils.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 } | 75 } |
76 | 76 |
77 // Check if a string addition will definitely result in creating a ConsString, | 77 // Check if a string addition will definitely result in creating a ConsString, |
78 // i.e. if the combined length of the resulting string exceeds the ConsString | 78 // i.e. if the combined length of the resulting string exceeds the ConsString |
79 // minimum length. | 79 // minimum length. |
80 bool ShouldCreateConsString() { | 80 bool ShouldCreateConsString() { |
81 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); | 81 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode()); |
82 if (BothInputsAre(Type::String()) || | 82 if (BothInputsAre(Type::String()) || |
83 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && | 83 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && |
84 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { | 84 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { |
85 if (left_type()->IsConstant() && | 85 if (left_type()->IsHeapConstant() && |
86 left_type()->AsConstant()->Value()->IsString()) { | 86 left_type()->AsHeapConstant()->Value()->IsString()) { |
87 Handle<String> left_string = | 87 Handle<String> left_string = |
88 Handle<String>::cast(left_type()->AsConstant()->Value()); | 88 Handle<String>::cast(left_type()->AsHeapConstant()->Value()); |
89 if (left_string->length() >= ConsString::kMinLength) return true; | 89 if (left_string->length() >= ConsString::kMinLength) return true; |
90 } | 90 } |
91 if (right_type()->IsConstant() && | 91 if (right_type()->IsHeapConstant() && |
92 right_type()->AsConstant()->Value()->IsString()) { | 92 right_type()->AsHeapConstant()->Value()->IsString()) { |
93 Handle<String> right_string = | 93 Handle<String> right_string = |
94 Handle<String>::cast(right_type()->AsConstant()->Value()); | 94 Handle<String>::cast(right_type()->AsHeapConstant()->Value()); |
95 if (right_string->length() >= ConsString::kMinLength) return true; | 95 if (right_string->length() >= ConsString::kMinLength) return true; |
96 } | 96 } |
97 } | 97 } |
98 return false; | 98 return false; |
99 } | 99 } |
100 | 100 |
101 void ConvertInputsToNumber() { | 101 void ConvertInputsToNumber() { |
102 // To convert the inputs to numbers, we have to provide frame states | 102 // To convert the inputs to numbers, we have to provide frame states |
103 // for lazy bailouts in the ToNumber conversions. | 103 // for lazy bailouts in the ToNumber conversions. |
104 // We use a little hack here: we take the frame state before the binary | 104 // We use a little hack here: we take the frame state before the binary |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 void update_effect(Node* effect) { | 440 void update_effect(Node* effect) { |
441 NodeProperties::ReplaceEffectInput(node_, effect); | 441 NodeProperties::ReplaceEffectInput(node_, effect); |
442 } | 442 } |
443 }; | 443 }; |
444 | 444 |
445 | 445 |
446 // TODO(turbofan): js-typed-lowering improvements possible | 446 // TODO(turbofan): js-typed-lowering improvements possible |
447 // - immediately put in type bounds for all new nodes | 447 // - immediately put in type bounds for all new nodes |
448 // - relax effects from generic but not-side-effecting operations | 448 // - relax effects from generic but not-side-effecting operations |
449 | 449 |
450 | |
451 JSTypedLowering::JSTypedLowering(Editor* editor, | 450 JSTypedLowering::JSTypedLowering(Editor* editor, |
452 CompilationDependencies* dependencies, | 451 CompilationDependencies* dependencies, |
453 Flags flags, JSGraph* jsgraph, Zone* zone) | 452 Flags flags, JSGraph* jsgraph, Zone* zone) |
454 : AdvancedReducer(editor), | 453 : AdvancedReducer(editor), |
455 dependencies_(dependencies), | 454 dependencies_(dependencies), |
456 flags_(flags), | 455 flags_(flags), |
457 jsgraph_(jsgraph), | 456 jsgraph_(jsgraph), |
458 the_hole_type_( | 457 the_hole_type_( |
459 Type::Constant(factory()->the_hole_value(), graph()->zone())), | 458 Type::HeapConstant(factory()->the_hole_value(), graph()->zone())), |
460 type_cache_(TypeCache::Get()) { | 459 type_cache_(TypeCache::Get()) { |
461 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { | 460 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { |
462 double min = kMinInt / (1 << k); | 461 double min = kMinInt / (1 << k); |
463 double max = kMaxInt / (1 << k); | 462 double max = kMaxInt / (1 << k); |
464 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); | 463 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); |
465 } | 464 } |
466 } | 465 } |
467 | 466 |
468 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { | 467 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { |
469 JSBinopReduction r(this, node); | 468 JSBinopReduction r(this, node); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 // Make sure {second} is actually a String. | 590 // Make sure {second} is actually a String. |
592 Type* second_type = NodeProperties::GetType(second); | 591 Type* second_type = NodeProperties::GetType(second); |
593 if (!second_type->Is(Type::String())) { | 592 if (!second_type->Is(Type::String())) { |
594 second = effect = | 593 second = effect = |
595 graph()->NewNode(simplified()->CheckString(), second, effect, control); | 594 graph()->NewNode(simplified()->CheckString(), second, effect, control); |
596 second_type = NodeProperties::GetType(second); | 595 second_type = NodeProperties::GetType(second); |
597 } | 596 } |
598 | 597 |
599 // Determine the {first} length. | 598 // Determine the {first} length. |
600 Node* first_length = | 599 Node* first_length = |
601 first_type->IsConstant() | 600 first_type->IsHeapConstant() |
602 ? jsgraph()->Constant( | 601 ? jsgraph()->Constant( |
603 Handle<String>::cast(first_type->AsConstant()->Value()) | 602 Handle<String>::cast(first_type->AsHeapConstant()->Value()) |
604 ->length()) | 603 ->length()) |
605 : effect = graph()->NewNode( | 604 : effect = graph()->NewNode( |
606 simplified()->LoadField(AccessBuilder::ForStringLength()), | 605 simplified()->LoadField(AccessBuilder::ForStringLength()), |
607 first, effect, control); | 606 first, effect, control); |
608 | 607 |
609 // Determine the {second} length. | 608 // Determine the {second} length. |
610 Node* second_length = | 609 Node* second_length = |
611 second_type->IsConstant() | 610 second_type->IsHeapConstant() |
612 ? jsgraph()->Constant( | 611 ? jsgraph()->Constant( |
613 Handle<String>::cast(second_type->AsConstant()->Value()) | 612 Handle<String>::cast(second_type->AsHeapConstant()->Value()) |
614 ->length()) | 613 ->length()) |
615 : effect = graph()->NewNode( | 614 : effect = graph()->NewNode( |
616 simplified()->LoadField(AccessBuilder::ForStringLength()), | 615 simplified()->LoadField(AccessBuilder::ForStringLength()), |
617 second, effect, control); | 616 second, effect, control); |
618 | 617 |
619 // Compute the resulting length. | 618 // Compute the resulting length. |
620 Node* length = | 619 Node* length = |
621 graph()->NewNode(simplified()->NumberAdd(), first_length, second_length); | 620 graph()->NewNode(simplified()->NumberAdd(), first_length, second_length); |
622 | 621 |
623 // Check if we would overflow the allowed maximum string length. | 622 // Check if we would overflow the allowed maximum string length. |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
973 } | 972 } |
974 ReplaceWithValue(node, input); | 973 ReplaceWithValue(node, input); |
975 return Replace(input); | 974 return Replace(input); |
976 } | 975 } |
977 return NoChange(); | 976 return NoChange(); |
978 } | 977 } |
979 | 978 |
980 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { | 979 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { |
981 // Try constant-folding of JSToNumber with constant inputs. | 980 // Try constant-folding of JSToNumber with constant inputs. |
982 Type* input_type = NodeProperties::GetType(input); | 981 Type* input_type = NodeProperties::GetType(input); |
983 if (input_type->IsConstant()) { | 982 if (input_type->IsHeapConstant()) { |
984 Handle<Object> input_value = input_type->AsConstant()->Value(); | 983 Handle<Object> input_value = input_type->AsHeapConstant()->Value(); |
985 if (input_value->IsString()) { | 984 if (input_value->IsString()) { |
986 return Replace(jsgraph()->Constant( | 985 return Replace(jsgraph()->Constant( |
987 String::ToNumber(Handle<String>::cast(input_value)))); | 986 String::ToNumber(Handle<String>::cast(input_value)))); |
988 } else if (input_value->IsOddball()) { | 987 } else if (input_value->IsOddball()) { |
989 return Replace(jsgraph()->Constant( | 988 return Replace(jsgraph()->Constant( |
990 Oddball::ToNumber(Handle<Oddball>::cast(input_value)))); | 989 Oddball::ToNumber(Handle<Oddball>::cast(input_value)))); |
991 } | 990 } |
992 } | 991 } |
993 if (input_type->Is(Type::Number())) { | 992 if (input_type->Is(Type::Number())) { |
994 // JSToNumber(x:number) => x | 993 // JSToNumber(x:number) => x |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 | 1272 |
1274 // If we are in a try block, don't optimize since the runtime call | 1273 // If we are in a try block, don't optimize since the runtime call |
1275 // in the proxy case can throw. | 1274 // in the proxy case can throw. |
1276 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); | 1275 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); |
1277 | 1276 |
1278 JSBinopReduction r(this, node); | 1277 JSBinopReduction r(this, node); |
1279 Node* object = r.left(); | 1278 Node* object = r.left(); |
1280 Node* effect = r.effect(); | 1279 Node* effect = r.effect(); |
1281 Node* control = r.control(); | 1280 Node* control = r.control(); |
1282 | 1281 |
1283 if (!r.right_type()->IsConstant() || | 1282 if (!r.right_type()->IsHeapConstant() || |
1284 !r.right_type()->AsConstant()->Value()->IsJSFunction()) { | 1283 !r.right_type()->AsHeapConstant()->Value()->IsJSFunction()) { |
1285 return NoChange(); | 1284 return NoChange(); |
1286 } | 1285 } |
1287 | 1286 |
1288 Handle<JSFunction> function = | 1287 Handle<JSFunction> function = |
1289 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value()); | 1288 Handle<JSFunction>::cast(r.right_type()->AsHeapConstant()->Value()); |
1290 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); | 1289 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); |
1291 | 1290 |
1292 // Make sure the prototype of {function} is the %FunctionPrototype%, and it | 1291 // Make sure the prototype of {function} is the %FunctionPrototype%, and it |
1293 // already has a meaningful initial map (i.e. we constructed at least one | 1292 // already has a meaningful initial map (i.e. we constructed at least one |
1294 // instance using the constructor {function}). | 1293 // instance using the constructor {function}). |
1295 if (function->map()->prototype() != function->native_context()->closure() || | 1294 if (function->map()->prototype() != function->native_context()->closure() || |
1296 function->map()->has_non_instance_prototype() || | 1295 function->map()->has_non_instance_prototype() || |
1297 !function->has_initial_map()) { | 1296 !function->has_initial_map()) { |
1298 return NoChange(); | 1297 return NoChange(); |
1299 } | 1298 } |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1478 // Check if {receiver} is known to be a receiver. | 1477 // Check if {receiver} is known to be a receiver. |
1479 if (receiver_type->Is(Type::Receiver())) { | 1478 if (receiver_type->Is(Type::Receiver())) { |
1480 ReplaceWithValue(node, receiver, effect, control); | 1479 ReplaceWithValue(node, receiver, effect, control); |
1481 return Replace(receiver); | 1480 return Replace(receiver); |
1482 } | 1481 } |
1483 | 1482 |
1484 // If the {receiver} is known to be null or undefined, we can just replace it | 1483 // If the {receiver} is known to be null or undefined, we can just replace it |
1485 // with the global proxy unconditionally. | 1484 // with the global proxy unconditionally. |
1486 if (receiver_type->Is(Type::NullOrUndefined()) || | 1485 if (receiver_type->Is(Type::NullOrUndefined()) || |
1487 mode == ConvertReceiverMode::kNullOrUndefined) { | 1486 mode == ConvertReceiverMode::kNullOrUndefined) { |
1488 if (context_type->IsConstant()) { | 1487 if (context_type->IsHeapConstant()) { |
1489 Handle<JSObject> global_proxy( | 1488 Handle<JSObject> global_proxy( |
1490 Handle<Context>::cast(context_type->AsConstant()->Value()) | 1489 Handle<Context>::cast(context_type->AsHeapConstant()->Value()) |
1491 ->global_proxy(), | 1490 ->global_proxy(), |
1492 isolate()); | 1491 isolate()); |
1493 receiver = jsgraph()->Constant(global_proxy); | 1492 receiver = jsgraph()->Constant(global_proxy); |
1494 } else { | 1493 } else { |
1495 Node* native_context = effect = graph()->NewNode( | 1494 Node* native_context = effect = graph()->NewNode( |
1496 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), | 1495 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
1497 context, context, effect); | 1496 context, context, effect); |
1498 receiver = effect = graph()->NewNode( | 1497 receiver = effect = graph()->NewNode( |
1499 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), | 1498 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), |
1500 native_context, native_context, effect); | 1499 native_context, native_context, effect); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1583 rconvert = econvert = graph()->NewNode( | 1582 rconvert = econvert = graph()->NewNode( |
1584 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), | 1583 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), |
1585 receiver, context, frame_state, econvert); | 1584 receiver, context, frame_state, econvert); |
1586 } | 1585 } |
1587 | 1586 |
1588 // Replace {receiver} with global proxy of {context}. | 1587 // Replace {receiver} with global proxy of {context}. |
1589 Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2); | 1588 Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2); |
1590 Node* eglobal = effect; | 1589 Node* eglobal = effect; |
1591 Node* rglobal; | 1590 Node* rglobal; |
1592 { | 1591 { |
1593 if (context_type->IsConstant()) { | 1592 if (context_type->IsHeapConstant()) { |
1594 Handle<JSObject> global_proxy( | 1593 Handle<JSObject> global_proxy( |
1595 Handle<Context>::cast(context_type->AsConstant()->Value()) | 1594 Handle<Context>::cast(context_type->AsHeapConstant()->Value()) |
1596 ->global_proxy(), | 1595 ->global_proxy(), |
1597 isolate()); | 1596 isolate()); |
1598 rglobal = jsgraph()->Constant(global_proxy); | 1597 rglobal = jsgraph()->Constant(global_proxy); |
1599 } else { | 1598 } else { |
1600 Node* native_context = eglobal = graph()->NewNode( | 1599 Node* native_context = eglobal = graph()->NewNode( |
1601 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), | 1600 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
1602 context, context, eglobal); | 1601 context, context, eglobal); |
1603 rglobal = eglobal = graph()->NewNode( | 1602 rglobal = eglobal = graph()->NewNode( |
1604 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), | 1603 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), |
1605 native_context, native_context, eglobal); | 1604 native_context, native_context, eglobal); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1708 CallConstructParameters const& p = CallConstructParametersOf(node->op()); | 1707 CallConstructParameters const& p = CallConstructParametersOf(node->op()); |
1709 DCHECK_LE(2u, p.arity()); | 1708 DCHECK_LE(2u, p.arity()); |
1710 int const arity = static_cast<int>(p.arity() - 2); | 1709 int const arity = static_cast<int>(p.arity() - 2); |
1711 Node* target = NodeProperties::GetValueInput(node, 0); | 1710 Node* target = NodeProperties::GetValueInput(node, 0); |
1712 Type* target_type = NodeProperties::GetType(target); | 1711 Type* target_type = NodeProperties::GetType(target); |
1713 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); | 1712 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); |
1714 Node* effect = NodeProperties::GetEffectInput(node); | 1713 Node* effect = NodeProperties::GetEffectInput(node); |
1715 Node* control = NodeProperties::GetControlInput(node); | 1714 Node* control = NodeProperties::GetControlInput(node); |
1716 | 1715 |
1717 // Check if {target} is a known JSFunction. | 1716 // Check if {target} is a known JSFunction. |
1718 if (target_type->IsConstant() && | 1717 if (target_type->IsHeapConstant() && |
1719 target_type->AsConstant()->Value()->IsJSFunction()) { | 1718 target_type->AsHeapConstant()->Value()->IsJSFunction()) { |
1720 Handle<JSFunction> function = | 1719 Handle<JSFunction> function = |
1721 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); | 1720 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value()); |
1722 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); | 1721 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); |
1723 const int builtin_index = shared->construct_stub()->builtin_index(); | 1722 const int builtin_index = shared->construct_stub()->builtin_index(); |
1724 const bool is_builtin = (builtin_index != -1); | 1723 const bool is_builtin = (builtin_index != -1); |
1725 | 1724 |
1726 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; | 1725 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; |
1727 | 1726 |
1728 if (is_builtin && Builtins::HasCppImplementation(builtin_index) && | 1727 if (is_builtin && Builtins::HasCppImplementation(builtin_index) && |
1729 !NeedsArgumentAdaptorFrame(shared, arity)) { | 1728 !NeedsArgumentAdaptorFrame(shared, arity)) { |
1730 // Patch {node} to a direct CEntryStub call. | 1729 // Patch {node} to a direct CEntryStub call. |
1731 | 1730 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1793 Node* frame_state = NodeProperties::FindFrameStateBefore(node); | 1792 Node* frame_state = NodeProperties::FindFrameStateBefore(node); |
1794 | 1793 |
1795 // Try to infer receiver {convert_mode} from {receiver} type. | 1794 // Try to infer receiver {convert_mode} from {receiver} type. |
1796 if (receiver_type->Is(Type::NullOrUndefined())) { | 1795 if (receiver_type->Is(Type::NullOrUndefined())) { |
1797 convert_mode = ConvertReceiverMode::kNullOrUndefined; | 1796 convert_mode = ConvertReceiverMode::kNullOrUndefined; |
1798 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) { | 1797 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) { |
1799 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; | 1798 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; |
1800 } | 1799 } |
1801 | 1800 |
1802 // Check if {target} is a known JSFunction. | 1801 // Check if {target} is a known JSFunction. |
1803 if (target_type->IsConstant() && | 1802 if (target_type->IsHeapConstant() && |
1804 target_type->AsConstant()->Value()->IsJSFunction()) { | 1803 target_type->AsHeapConstant()->Value()->IsJSFunction()) { |
1805 Handle<JSFunction> function = | 1804 Handle<JSFunction> function = |
1806 Handle<JSFunction>::cast(target_type->AsConstant()->Value()); | 1805 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value()); |
1807 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); | 1806 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); |
1808 const int builtin_index = shared->code()->builtin_index(); | 1807 const int builtin_index = shared->code()->builtin_index(); |
1809 const bool is_builtin = (builtin_index != -1); | 1808 const bool is_builtin = (builtin_index != -1); |
1810 | 1809 |
1811 // Class constructors are callable, but [[Call]] will raise an exception. | 1810 // Class constructors are callable, but [[Call]] will raise an exception. |
1812 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). | 1811 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). |
1813 if (IsClassConstructor(shared->kind())) return NoChange(); | 1812 if (IsClassConstructor(shared->kind())) return NoChange(); |
1814 | 1813 |
1815 // Load the context from the {target}. | 1814 // Load the context from the {target}. |
1816 Node* context = effect = graph()->NewNode( | 1815 Node* context = effect = graph()->NewNode( |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2141 } | 2140 } |
2142 | 2141 |
2143 | 2142 |
2144 CompilationDependencies* JSTypedLowering::dependencies() const { | 2143 CompilationDependencies* JSTypedLowering::dependencies() const { |
2145 return dependencies_; | 2144 return dependencies_; |
2146 } | 2145 } |
2147 | 2146 |
2148 } // namespace compiler | 2147 } // namespace compiler |
2149 } // namespace internal | 2148 } // namespace internal |
2150 } // namespace v8 | 2149 } // namespace v8 |
OLD | NEW |