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 |