| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/code-stubs.h" | 5 #include "src/code-stubs.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| 11 #include "src/code-stub-assembler.h" | 11 #include "src/code-stub-assembler.h" |
| 12 #include "src/factory.h" | 12 #include "src/factory.h" |
| 13 #include "src/gdb-jit.h" | 13 #include "src/gdb-jit.h" |
| 14 #include "src/ic/handler-compiler.h" | 14 #include "src/ic/handler-compiler.h" |
| 15 #include "src/ic/ic.h" | 15 #include "src/ic/ic.h" |
| 16 #include "src/macro-assembler.h" | 16 #include "src/macro-assembler.h" |
| 17 #include "src/parsing/parser.h" | 17 #include "src/parsing/parser.h" |
| 18 | 18 |
| 19 namespace v8 { | 19 namespace v8 { |
| 20 namespace internal { | 20 namespace internal { |
| 21 | 21 |
| 22 enum class StrictEqualsFlags : unsigned char { |
| 23 Normal = 0, |
| 24 NanEqualsNan = 1 << 0, |
| 25 }; |
| 26 |
| 27 static inline bool operator&(StrictEqualsFlags lhs, StrictEqualsFlags rhs) { |
| 28 return (static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs)) != |
| 29 0; |
| 30 } |
| 22 | 31 |
| 23 RUNTIME_FUNCTION(UnexpectedStubMiss) { | 32 RUNTIME_FUNCTION(UnexpectedStubMiss) { |
| 24 FATAL("Unexpected deopt of a stub"); | 33 FATAL("Unexpected deopt of a stub"); |
| 25 return Smi::FromInt(0); | 34 return Smi::FromInt(0); |
| 26 } | 35 } |
| 27 | 36 |
| 28 | 37 |
| 29 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub) | 38 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub) |
| 30 : call_descriptor_(stub->GetCallInterfaceDescriptor()), | 39 : call_descriptor_(stub->GetCallInterfaceDescriptor()), |
| 31 stack_parameter_count_(no_reg), | 40 stack_parameter_count_(no_reg), |
| (...skipping 2227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2259 } | 2268 } |
| 2260 | 2269 |
| 2261 assembler->Bind(&end); | 2270 assembler->Bind(&end); |
| 2262 return result.value(); | 2271 return result.value(); |
| 2263 } | 2272 } |
| 2264 | 2273 |
| 2265 enum ResultMode { kDontNegateResult, kNegateResult }; | 2274 enum ResultMode { kDontNegateResult, kNegateResult }; |
| 2266 | 2275 |
| 2267 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, | 2276 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, |
| 2268 CodeStubAssembler::Label* if_equal, | 2277 CodeStubAssembler::Label* if_equal, |
| 2269 CodeStubAssembler::Label* if_notequal) { | 2278 CodeStubAssembler::Label* if_notequal, |
| 2279 StrictEqualsFlags flags) { |
| 2270 // In case of abstract or strict equality checks, we need additional checks | 2280 // In case of abstract or strict equality checks, we need additional checks |
| 2271 // for NaN values because they are not considered equal, even if both the | 2281 // for NaN values because they are not considered equal, even if both the |
| 2272 // left and the right hand side reference exactly the same value. | 2282 // left and the right hand side reference exactly the same value. |
| 2273 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it | 2283 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it |
| 2274 // seems to be what is tested in the current SIMD.js testsuite. | 2284 // seems to be what is tested in the current SIMD.js testsuite. |
| 2275 | 2285 |
| 2276 typedef CodeStubAssembler::Label Label; | 2286 typedef CodeStubAssembler::Label Label; |
| 2277 typedef compiler::Node Node; | 2287 typedef compiler::Node Node; |
| 2278 | 2288 |
| 2279 // Check if {value} is a Smi or a HeapObject. | 2289 // Check if {value} is a Smi or a HeapObject. |
| 2280 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | 2290 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
| 2281 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, | 2291 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, |
| 2282 &if_valueisnotsmi); | 2292 &if_valueisnotsmi); |
| 2283 | 2293 |
| 2284 assembler->Bind(&if_valueisnotsmi); | 2294 assembler->Bind(&if_valueisnotsmi); |
| 2285 { | 2295 { |
| 2286 // Load the map of {value}. | 2296 // Load the map of {value}. |
| 2287 Node* value_map = assembler->LoadMap(value); | 2297 Node* value_map = assembler->LoadMap(value); |
| 2288 | 2298 |
| 2289 // Check if {value} (and therefore {rhs}) is a HeapNumber. | 2299 // Check if {value} (and therefore {rhs}) is a HeapNumber. |
| 2290 Node* number_map = assembler->HeapNumberMapConstant(); | 2300 Node* number_map = assembler->HeapNumberMapConstant(); |
| 2291 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); | 2301 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); |
| 2292 assembler->Branch(assembler->WordEqual(value_map, number_map), | 2302 assembler->Branch(assembler->WordEqual(value_map, number_map), |
| 2293 &if_valueisnumber, &if_valueisnotnumber); | 2303 &if_valueisnumber, &if_valueisnotnumber); |
| 2294 | 2304 |
| 2295 assembler->Bind(&if_valueisnumber); | 2305 assembler->Bind(&if_valueisnumber); |
| 2296 { | 2306 { |
| 2297 // Convert {value} (and therefore {rhs}) to floating point value. | 2307 if (flags & StrictEqualsFlags::NanEqualsNan) { |
| 2298 Node* value_value = assembler->LoadHeapNumberValue(value); | 2308 // NaN === NaN --- No special treatment |
| 2309 assembler->Goto(if_equal); |
| 2310 } else { |
| 2311 // Convert {value} (and therefore {rhs}) to floating point value. |
| 2312 Node* value_value = assembler->LoadHeapNumberValue(value); |
| 2299 | 2313 |
| 2300 // Check if the HeapNumber value is a NaN. | 2314 // Check if the HeapNumber value is a NaN. |
| 2301 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); | 2315 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); |
| 2316 } |
| 2302 } | 2317 } |
| 2303 | 2318 |
| 2304 assembler->Bind(&if_valueisnotnumber); | 2319 assembler->Bind(&if_valueisnotnumber); |
| 2305 assembler->Goto(if_equal); | 2320 assembler->Goto(if_equal); |
| 2306 } | 2321 } |
| 2307 | 2322 |
| 2308 assembler->Bind(&if_valueissmi); | 2323 assembler->Bind(&if_valueissmi); |
| 2309 assembler->Goto(if_equal); | 2324 assembler->Goto(if_equal); |
| 2310 } | 2325 } |
| 2311 | 2326 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2424 rhs = var_rhs.value(); | 2439 rhs = var_rhs.value(); |
| 2425 | 2440 |
| 2426 // Check if {lhs} and {rhs} refer to the same object. | 2441 // Check if {lhs} and {rhs} refer to the same object. |
| 2427 Label if_same(assembler), if_notsame(assembler); | 2442 Label if_same(assembler), if_notsame(assembler); |
| 2428 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | 2443 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 2429 | 2444 |
| 2430 assembler->Bind(&if_same); | 2445 assembler->Bind(&if_same); |
| 2431 { | 2446 { |
| 2432 // The {lhs} and {rhs} reference the exact same value, yet we need special | 2447 // The {lhs} and {rhs} reference the exact same value, yet we need special |
| 2433 // treatment for HeapNumber, as NaN is not equal to NaN. | 2448 // treatment for HeapNumber, as NaN is not equal to NaN. |
| 2434 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); | 2449 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal, |
| 2450 StrictEqualsFlags::Normal); |
| 2435 } | 2451 } |
| 2436 | 2452 |
| 2437 assembler->Bind(&if_notsame); | 2453 assembler->Bind(&if_notsame); |
| 2438 { | 2454 { |
| 2439 // Check if {lhs} is a Smi or a HeapObject. | 2455 // Check if {lhs} is a Smi or a HeapObject. |
| 2440 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | 2456 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
| 2441 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, | 2457 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, |
| 2442 &if_lhsisnotsmi); | 2458 &if_lhsisnotsmi); |
| 2443 | 2459 |
| 2444 assembler->Bind(&if_lhsissmi); | 2460 assembler->Bind(&if_lhsissmi); |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2924 assembler->Goto(&end); | 2940 assembler->Goto(&end); |
| 2925 } | 2941 } |
| 2926 | 2942 |
| 2927 assembler->Bind(&end); | 2943 assembler->Bind(&end); |
| 2928 return result.value(); | 2944 return result.value(); |
| 2929 } | 2945 } |
| 2930 | 2946 |
| 2931 compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler, | 2947 compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler, |
| 2932 ResultMode mode, compiler::Node* lhs, | 2948 ResultMode mode, compiler::Node* lhs, |
| 2933 compiler::Node* rhs, | 2949 compiler::Node* rhs, |
| 2934 compiler::Node* context) { | 2950 compiler::Node* context, |
| 2951 StrictEqualsFlags flags) { |
| 2935 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | 2952 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
| 2936 // mode; for kNegateResult mode we properly negate the result. | 2953 // mode; for kNegateResult mode we properly negate the result. |
| 2937 // | 2954 // |
| 2938 // if (lhs == rhs) { | 2955 // if (lhs == rhs) { |
| 2939 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; | 2956 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; |
| 2940 // return true; | 2957 // return true; |
| 2941 // } | 2958 // } |
| 2942 // if (!lhs->IsSmi()) { | 2959 // if (!lhs->IsSmi()) { |
| 2943 // if (lhs->IsHeapNumber()) { | 2960 // if (lhs->IsHeapNumber()) { |
| 2944 // if (rhs->IsSmi()) { | 2961 // if (rhs->IsSmi()) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2988 Variable result(assembler, MachineRepresentation::kTagged); | 3005 Variable result(assembler, MachineRepresentation::kTagged); |
| 2989 | 3006 |
| 2990 // Check if {lhs} and {rhs} refer to the same object. | 3007 // Check if {lhs} and {rhs} refer to the same object. |
| 2991 Label if_same(assembler), if_notsame(assembler); | 3008 Label if_same(assembler), if_notsame(assembler); |
| 2992 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | 3009 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 2993 | 3010 |
| 2994 assembler->Bind(&if_same); | 3011 assembler->Bind(&if_same); |
| 2995 { | 3012 { |
| 2996 // The {lhs} and {rhs} reference the exact same value, yet we need special | 3013 // The {lhs} and {rhs} reference the exact same value, yet we need special |
| 2997 // treatment for HeapNumber, as NaN is not equal to NaN. | 3014 // treatment for HeapNumber, as NaN is not equal to NaN. |
| 2998 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); | 3015 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal, flags); |
| 2999 } | 3016 } |
| 3000 | 3017 |
| 3001 assembler->Bind(&if_notsame); | 3018 assembler->Bind(&if_notsame); |
| 3002 { | 3019 { |
| 3003 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, | 3020 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, |
| 3004 // String and Simd128Value they can still be considered equal. | 3021 // String and Simd128Value they can still be considered equal. |
| 3005 Node* number_map = assembler->HeapNumberMapConstant(); | 3022 Node* number_map = assembler->HeapNumberMapConstant(); |
| 3006 | 3023 |
| 3007 // Check if {lhs} is a Smi or a HeapObject. | 3024 // Check if {lhs} is a Smi or a HeapObject. |
| 3008 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | 3025 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3045 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | 3062 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); |
| 3046 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | 3063 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 3047 &if_rhsisnumber, &if_rhsisnotnumber); | 3064 &if_rhsisnumber, &if_rhsisnotnumber); |
| 3048 | 3065 |
| 3049 assembler->Bind(&if_rhsisnumber); | 3066 assembler->Bind(&if_rhsisnumber); |
| 3050 { | 3067 { |
| 3051 // Convert {lhs} and {rhs} to floating point values. | 3068 // Convert {lhs} and {rhs} to floating point values. |
| 3052 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | 3069 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
| 3053 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | 3070 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); |
| 3054 | 3071 |
| 3072 if (flags & StrictEqualsFlags::NanEqualsNan) { |
| 3073 Label isnan(assembler), isnotnan(assembler); |
| 3074 assembler->BranchIfFloat64IsNaN(lhs_value, &isnan, &isnotnan); |
| 3075 |
| 3076 assembler->Bind(&isnan); |
| 3077 assembler->BranchIfFloat64IsNaN(rhs_value, &if_equal, &isnotnan); |
| 3078 |
| 3079 assembler->Bind(&isnotnan); |
| 3080 } |
| 3081 |
| 3055 // Perform a floating point comparison of {lhs} and {rhs}. | 3082 // Perform a floating point comparison of {lhs} and {rhs}. |
| 3056 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | 3083 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, |
| 3057 &if_notequal); | 3084 &if_notequal); |
| 3058 } | 3085 } |
| 3059 | 3086 |
| 3060 assembler->Bind(&if_rhsisnotnumber); | 3087 assembler->Bind(&if_rhsisnotnumber); |
| 3061 assembler->Goto(&if_notequal); | 3088 assembler->Goto(&if_notequal); |
| 3062 } | 3089 } |
| 3063 } | 3090 } |
| 3064 | 3091 |
| (...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3620 compiler::Node* lhs, compiler::Node* rhs, | 3647 compiler::Node* lhs, compiler::Node* rhs, |
| 3621 compiler::Node* context) { | 3648 compiler::Node* context) { |
| 3622 return GenerateEqual(assembler, kNegateResult, lhs, rhs, context); | 3649 return GenerateEqual(assembler, kNegateResult, lhs, rhs, context); |
| 3623 } | 3650 } |
| 3624 | 3651 |
| 3625 // static | 3652 // static |
| 3626 compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler, | 3653 compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler, |
| 3627 compiler::Node* lhs, | 3654 compiler::Node* lhs, |
| 3628 compiler::Node* rhs, | 3655 compiler::Node* rhs, |
| 3629 compiler::Node* context) { | 3656 compiler::Node* context) { |
| 3630 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context); | 3657 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context, |
| 3658 StrictEqualsFlags::Normal); |
| 3631 } | 3659 } |
| 3632 | 3660 |
| 3633 // static | 3661 // static |
| 3634 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, | 3662 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, |
| 3635 compiler::Node* lhs, | 3663 compiler::Node* lhs, |
| 3636 compiler::Node* rhs, | 3664 compiler::Node* rhs, |
| 3637 compiler::Node* context) { | 3665 compiler::Node* context) { |
| 3638 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); | 3666 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context, |
| 3667 StrictEqualsFlags::Normal); |
| 3668 } |
| 3669 |
| 3670 compiler::Node* SameValueZeroStub::Generate(CodeStubAssembler* assembler, |
| 3671 compiler::Node* lhs, |
| 3672 compiler::Node* rhs, |
| 3673 compiler::Node* context) { |
| 3674 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context, |
| 3675 StrictEqualsFlags::NanEqualsNan); |
| 3639 } | 3676 } |
| 3640 | 3677 |
| 3641 void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 3678 void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
| 3642 GenerateStringEqual(assembler, kDontNegateResult); | 3679 GenerateStringEqual(assembler, kDontNegateResult); |
| 3643 } | 3680 } |
| 3644 | 3681 |
| 3645 void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 3682 void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
| 3646 GenerateStringEqual(assembler, kNegateResult); | 3683 GenerateStringEqual(assembler, kNegateResult); |
| 3647 } | 3684 } |
| 3648 | 3685 |
| (...skipping 1287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4936 if (type->Is(Type::UntaggedPointer())) { | 4973 if (type->Is(Type::UntaggedPointer())) { |
| 4937 return Representation::External(); | 4974 return Representation::External(); |
| 4938 } | 4975 } |
| 4939 | 4976 |
| 4940 DCHECK(!type->Is(Type::Untagged())); | 4977 DCHECK(!type->Is(Type::Untagged())); |
| 4941 return Representation::Tagged(); | 4978 return Representation::Tagged(); |
| 4942 } | 4979 } |
| 4943 | 4980 |
| 4944 } // namespace internal | 4981 } // namespace internal |
| 4945 } // namespace v8 | 4982 } // namespace v8 |
| OLD | NEW |