| 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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
| 8 #include "src/code-stub-assembler.h" |
| 8 | 9 |
| 9 namespace v8 { | 10 namespace v8 { |
| 10 namespace internal { | 11 namespace internal { |
| 11 | 12 |
| 13 class NumberBuiltinsAssembler : public CodeStubAssembler { |
| 14 public: |
| 15 explicit NumberBuiltinsAssembler(compiler::CodeAssemblerState* state) |
| 16 : CodeStubAssembler(state) {} |
| 17 |
| 18 protected: |
| 19 // TODO(jkummerow): Add useful helpers here, and derive from |
| 20 // NumberBuiltinsAssembler below. |
| 21 }; |
| 22 |
| 12 // ----------------------------------------------------------------------------- | 23 // ----------------------------------------------------------------------------- |
| 13 // ES6 section 20.1 Number Objects | 24 // ES6 section 20.1 Number Objects |
| 14 | 25 |
| 15 // ES6 section 20.1.2.2 Number.isFinite ( number ) | 26 // ES6 section 20.1.2.2 Number.isFinite ( number ) |
| 16 void Builtins::Generate_NumberIsFinite(compiler::CodeAssemblerState* state) { | 27 TF_BUILTIN(NumberIsFinite, CodeStubAssembler) { |
| 17 typedef CodeStubAssembler::Label Label; | 28 Node* number = Parameter(1); |
| 18 typedef compiler::Node Node; | 29 |
| 19 CodeStubAssembler assembler(state); | 30 Label return_true(this), return_false(this); |
| 20 | 31 |
| 21 Node* number = assembler.Parameter(1); | 32 // Check if {number} is a Smi. |
| 22 | 33 GotoIf(TaggedIsSmi(number), &return_true); |
| 23 Label return_true(&assembler), return_false(&assembler); | 34 |
| 24 | 35 // Check if {number} is a HeapNumber. |
| 25 // Check if {number} is a Smi. | 36 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
| 26 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | 37 &return_false); |
| 27 | |
| 28 // Check if {number} is a HeapNumber. | |
| 29 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
| 30 assembler.HeapNumberMapConstant()), | |
| 31 &return_false); | |
| 32 | 38 |
| 33 // Check if {number} contains a finite, non-NaN value. | 39 // Check if {number} contains a finite, non-NaN value. |
| 34 Node* number_value = assembler.LoadHeapNumberValue(number); | 40 Node* number_value = LoadHeapNumberValue(number); |
| 35 assembler.BranchIfFloat64IsNaN( | 41 BranchIfFloat64IsNaN(Float64Sub(number_value, number_value), &return_false, |
| 36 assembler.Float64Sub(number_value, number_value), &return_false, | 42 &return_true); |
| 37 &return_true); | 43 |
| 38 | 44 Bind(&return_true); |
| 39 assembler.Bind(&return_true); | 45 Return(BooleanConstant(true)); |
| 40 assembler.Return(assembler.BooleanConstant(true)); | 46 |
| 41 | 47 Bind(&return_false); |
| 42 assembler.Bind(&return_false); | 48 Return(BooleanConstant(false)); |
| 43 assembler.Return(assembler.BooleanConstant(false)); | |
| 44 } | 49 } |
| 45 | 50 |
| 46 // ES6 section 20.1.2.3 Number.isInteger ( number ) | 51 // ES6 section 20.1.2.3 Number.isInteger ( number ) |
| 47 void Builtins::Generate_NumberIsInteger(compiler::CodeAssemblerState* state) { | 52 TF_BUILTIN(NumberIsInteger, CodeStubAssembler) { |
| 48 typedef CodeStubAssembler::Label Label; | 53 Node* number = Parameter(1); |
| 49 typedef compiler::Node Node; | 54 |
| 50 CodeStubAssembler assembler(state); | 55 Label return_true(this), return_false(this); |
| 51 | 56 |
| 52 Node* number = assembler.Parameter(1); | 57 // Check if {number} is a Smi. |
| 53 | 58 GotoIf(TaggedIsSmi(number), &return_true); |
| 54 Label return_true(&assembler), return_false(&assembler); | 59 |
| 55 | 60 // Check if {number} is a HeapNumber. |
| 56 // Check if {number} is a Smi. | 61 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
| 57 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | 62 &return_false); |
| 58 | |
| 59 // Check if {number} is a HeapNumber. | |
| 60 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
| 61 assembler.HeapNumberMapConstant()), | |
| 62 &return_false); | |
| 63 | 63 |
| 64 // Load the actual value of {number}. | 64 // Load the actual value of {number}. |
| 65 Node* number_value = assembler.LoadHeapNumberValue(number); | 65 Node* number_value = LoadHeapNumberValue(number); |
| 66 | 66 |
| 67 // Truncate the value of {number} to an integer (or an infinity). | 67 // Truncate the value of {number} to an integer (or an infinity). |
| 68 Node* integer = assembler.Float64Trunc(number_value); | 68 Node* integer = Float64Trunc(number_value); |
| 69 | 69 |
| 70 // Check if {number}s value matches the integer (ruling out the infinities). | 70 // Check if {number}s value matches the integer (ruling out the infinities). |
| 71 assembler.Branch( | 71 Branch(Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)), |
| 72 assembler.Float64Equal(assembler.Float64Sub(number_value, integer), | 72 &return_true, &return_false); |
| 73 assembler.Float64Constant(0.0)), | 73 |
| 74 &return_true, &return_false); | 74 Bind(&return_true); |
| 75 | 75 Return(BooleanConstant(true)); |
| 76 assembler.Bind(&return_true); | 76 |
| 77 assembler.Return(assembler.BooleanConstant(true)); | 77 Bind(&return_false); |
| 78 | 78 Return(BooleanConstant(false)); |
| 79 assembler.Bind(&return_false); | |
| 80 assembler.Return(assembler.BooleanConstant(false)); | |
| 81 } | 79 } |
| 82 | 80 |
| 83 // ES6 section 20.1.2.4 Number.isNaN ( number ) | 81 // ES6 section 20.1.2.4 Number.isNaN ( number ) |
| 84 void Builtins::Generate_NumberIsNaN(compiler::CodeAssemblerState* state) { | 82 TF_BUILTIN(NumberIsNaN, CodeStubAssembler) { |
| 85 typedef CodeStubAssembler::Label Label; | 83 Node* number = Parameter(1); |
| 86 typedef compiler::Node Node; | 84 |
| 87 CodeStubAssembler assembler(state); | 85 Label return_true(this), return_false(this); |
| 88 | 86 |
| 89 Node* number = assembler.Parameter(1); | 87 // Check if {number} is a Smi. |
| 90 | 88 GotoIf(TaggedIsSmi(number), &return_false); |
| 91 Label return_true(&assembler), return_false(&assembler); | 89 |
| 92 | 90 // Check if {number} is a HeapNumber. |
| 93 // Check if {number} is a Smi. | 91 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
| 94 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_false); | 92 &return_false); |
| 95 | |
| 96 // Check if {number} is a HeapNumber. | |
| 97 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
| 98 assembler.HeapNumberMapConstant()), | |
| 99 &return_false); | |
| 100 | 93 |
| 101 // Check if {number} contains a NaN value. | 94 // Check if {number} contains a NaN value. |
| 102 Node* number_value = assembler.LoadHeapNumberValue(number); | 95 Node* number_value = LoadHeapNumberValue(number); |
| 103 assembler.BranchIfFloat64IsNaN(number_value, &return_true, &return_false); | 96 BranchIfFloat64IsNaN(number_value, &return_true, &return_false); |
| 104 | 97 |
| 105 assembler.Bind(&return_true); | 98 Bind(&return_true); |
| 106 assembler.Return(assembler.BooleanConstant(true)); | 99 Return(BooleanConstant(true)); |
| 107 | 100 |
| 108 assembler.Bind(&return_false); | 101 Bind(&return_false); |
| 109 assembler.Return(assembler.BooleanConstant(false)); | 102 Return(BooleanConstant(false)); |
| 110 } | 103 } |
| 111 | 104 |
| 112 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) | 105 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) |
| 113 void Builtins::Generate_NumberIsSafeInteger( | 106 TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) { |
| 114 compiler::CodeAssemblerState* state) { | 107 Node* number = Parameter(1); |
| 115 typedef CodeStubAssembler::Label Label; | 108 |
| 116 typedef compiler::Node Node; | 109 Label return_true(this), return_false(this); |
| 117 CodeStubAssembler assembler(state); | 110 |
| 118 | 111 // Check if {number} is a Smi. |
| 119 Node* number = assembler.Parameter(1); | 112 GotoIf(TaggedIsSmi(number), &return_true); |
| 120 | 113 |
| 121 Label return_true(&assembler), return_false(&assembler); | 114 // Check if {number} is a HeapNumber. |
| 122 | 115 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
| 123 // Check if {number} is a Smi. | 116 &return_false); |
| 124 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | |
| 125 | |
| 126 // Check if {number} is a HeapNumber. | |
| 127 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
| 128 assembler.HeapNumberMapConstant()), | |
| 129 &return_false); | |
| 130 | 117 |
| 131 // Load the actual value of {number}. | 118 // Load the actual value of {number}. |
| 132 Node* number_value = assembler.LoadHeapNumberValue(number); | 119 Node* number_value = LoadHeapNumberValue(number); |
| 133 | 120 |
| 134 // Truncate the value of {number} to an integer (or an infinity). | 121 // Truncate the value of {number} to an integer (or an infinity). |
| 135 Node* integer = assembler.Float64Trunc(number_value); | 122 Node* integer = Float64Trunc(number_value); |
| 136 | 123 |
| 137 // Check if {number}s value matches the integer (ruling out the infinities). | 124 // Check if {number}s value matches the integer (ruling out the infinities). |
| 138 assembler.GotoUnless( | 125 GotoUnless( |
| 139 assembler.Float64Equal(assembler.Float64Sub(number_value, integer), | 126 Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)), |
| 140 assembler.Float64Constant(0.0)), | |
| 141 &return_false); | 127 &return_false); |
| 142 | 128 |
| 143 // Check if the {integer} value is in safe integer range. | 129 // Check if the {integer} value is in safe integer range. |
| 144 assembler.Branch(assembler.Float64LessThanOrEqual( | 130 Branch(Float64LessThanOrEqual(Float64Abs(integer), |
| 145 assembler.Float64Abs(integer), | 131 Float64Constant(kMaxSafeInteger)), |
| 146 assembler.Float64Constant(kMaxSafeInteger)), | 132 &return_true, &return_false); |
| 147 &return_true, &return_false); | 133 |
| 148 | 134 Bind(&return_true); |
| 149 assembler.Bind(&return_true); | 135 Return(BooleanConstant(true)); |
| 150 assembler.Return(assembler.BooleanConstant(true)); | 136 |
| 151 | 137 Bind(&return_false); |
| 152 assembler.Bind(&return_false); | 138 Return(BooleanConstant(false)); |
| 153 assembler.Return(assembler.BooleanConstant(false)); | |
| 154 } | 139 } |
| 155 | 140 |
| 156 // ES6 section 20.1.2.12 Number.parseFloat ( string ) | 141 // ES6 section 20.1.2.12 Number.parseFloat ( string ) |
| 157 void Builtins::Generate_NumberParseFloat(compiler::CodeAssemblerState* state) { | 142 TF_BUILTIN(NumberParseFloat, CodeStubAssembler) { |
| 158 typedef CodeStubAssembler::Label Label; | 143 Node* context = Parameter(4); |
| 159 typedef compiler::Node Node; | |
| 160 typedef CodeStubAssembler::Variable Variable; | |
| 161 CodeStubAssembler assembler(state); | |
| 162 | |
| 163 Node* context = assembler.Parameter(4); | |
| 164 | 144 |
| 165 // We might need to loop once for ToString conversion. | 145 // We might need to loop once for ToString conversion. |
| 166 Variable var_input(&assembler, MachineRepresentation::kTagged); | 146 Variable var_input(this, MachineRepresentation::kTagged); |
| 167 Label loop(&assembler, &var_input); | 147 Label loop(this, &var_input); |
| 168 var_input.Bind(assembler.Parameter(1)); | 148 var_input.Bind(Parameter(1)); |
| 169 assembler.Goto(&loop); | 149 Goto(&loop); |
| 170 assembler.Bind(&loop); | 150 Bind(&loop); |
| 171 { | 151 { |
| 172 // Load the current {input} value. | 152 // Load the current {input} value. |
| 173 Node* input = var_input.value(); | 153 Node* input = var_input.value(); |
| 174 | 154 |
| 175 // Check if the {input} is a HeapObject or a Smi. | 155 // Check if the {input} is a HeapObject or a Smi. |
| 176 Label if_inputissmi(&assembler), if_inputisnotsmi(&assembler); | 156 Label if_inputissmi(this), if_inputisnotsmi(this); |
| 177 assembler.Branch(assembler.TaggedIsSmi(input), &if_inputissmi, | 157 Branch(TaggedIsSmi(input), &if_inputissmi, &if_inputisnotsmi); |
| 178 &if_inputisnotsmi); | 158 |
| 179 | 159 Bind(&if_inputissmi); |
| 180 assembler.Bind(&if_inputissmi); | |
| 181 { | 160 { |
| 182 // The {input} is already a Number, no need to do anything. | 161 // The {input} is already a Number, no need to do anything. |
| 183 assembler.Return(input); | 162 Return(input); |
| 184 } | 163 } |
| 185 | 164 |
| 186 assembler.Bind(&if_inputisnotsmi); | 165 Bind(&if_inputisnotsmi); |
| 187 { | 166 { |
| 188 // The {input} is a HeapObject, check if it's already a String. | 167 // The {input} is a HeapObject, check if it's already a String. |
| 189 Label if_inputisstring(&assembler), if_inputisnotstring(&assembler); | 168 Label if_inputisstring(this), if_inputisnotstring(this); |
| 190 Node* input_map = assembler.LoadMap(input); | 169 Node* input_map = LoadMap(input); |
| 191 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 170 Node* input_instance_type = LoadMapInstanceType(input_map); |
| 192 assembler.Branch(assembler.IsStringInstanceType(input_instance_type), | 171 Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, |
| 193 &if_inputisstring, &if_inputisnotstring); | 172 &if_inputisnotstring); |
| 194 | 173 |
| 195 assembler.Bind(&if_inputisstring); | 174 Bind(&if_inputisstring); |
| 196 { | 175 { |
| 197 // The {input} is already a String, check if {input} contains | 176 // The {input} is already a String, check if {input} contains |
| 198 // a cached array index. | 177 // a cached array index. |
| 199 Label if_inputcached(&assembler), if_inputnotcached(&assembler); | 178 Label if_inputcached(this), if_inputnotcached(this); |
| 200 Node* input_hash = assembler.LoadNameHashField(input); | 179 Node* input_hash = LoadNameHashField(input); |
| 201 Node* input_bit = assembler.Word32And( | 180 Node* input_bit = Word32And( |
| 202 input_hash, | 181 input_hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
| 203 assembler.Int32Constant(String::kContainsCachedArrayIndexMask)); | 182 Branch(Word32Equal(input_bit, Int32Constant(0)), &if_inputcached, |
| 204 assembler.Branch( | 183 &if_inputnotcached); |
| 205 assembler.Word32Equal(input_bit, assembler.Int32Constant(0)), | 184 |
| 206 &if_inputcached, &if_inputnotcached); | 185 Bind(&if_inputcached); |
| 207 | |
| 208 assembler.Bind(&if_inputcached); | |
| 209 { | 186 { |
| 210 // Just return the {input}s cached array index. | 187 // Just return the {input}s cached array index. |
| 211 Node* input_array_index = | 188 Node* input_array_index = |
| 212 assembler.DecodeWordFromWord32<String::ArrayIndexValueBits>( | 189 DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); |
| 213 input_hash); | 190 Return(SmiTag(input_array_index)); |
| 214 assembler.Return(assembler.SmiTag(input_array_index)); | 191 } |
| 215 } | 192 |
| 216 | 193 Bind(&if_inputnotcached); |
| 217 assembler.Bind(&if_inputnotcached); | |
| 218 { | 194 { |
| 219 // Need to fall back to the runtime to convert {input} to double. | 195 // Need to fall back to the runtime to convert {input} to double. |
| 220 assembler.Return(assembler.CallRuntime(Runtime::kStringParseFloat, | 196 Return(CallRuntime(Runtime::kStringParseFloat, context, input)); |
| 221 context, input)); | |
| 222 } | 197 } |
| 223 } | 198 } |
| 224 | 199 |
| 225 assembler.Bind(&if_inputisnotstring); | 200 Bind(&if_inputisnotstring); |
| 226 { | 201 { |
| 227 // The {input} is neither a String nor a Smi, check for HeapNumber. | 202 // The {input} is neither a String nor a Smi, check for HeapNumber. |
| 228 Label if_inputisnumber(&assembler), | 203 Label if_inputisnumber(this), |
| 229 if_inputisnotnumber(&assembler, Label::kDeferred); | 204 if_inputisnotnumber(this, Label::kDeferred); |
| 230 assembler.Branch( | 205 Branch(WordEqual(input_map, HeapNumberMapConstant()), &if_inputisnumber, |
| 231 assembler.WordEqual(input_map, assembler.HeapNumberMapConstant()), | 206 &if_inputisnotnumber); |
| 232 &if_inputisnumber, &if_inputisnotnumber); | 207 |
| 233 | 208 Bind(&if_inputisnumber); |
| 234 assembler.Bind(&if_inputisnumber); | |
| 235 { | 209 { |
| 236 // The {input} is already a Number, take care of -0. | 210 // The {input} is already a Number, take care of -0. |
| 237 Label if_inputiszero(&assembler), if_inputisnotzero(&assembler); | 211 Label if_inputiszero(this), if_inputisnotzero(this); |
| 238 Node* input_value = assembler.LoadHeapNumberValue(input); | 212 Node* input_value = LoadHeapNumberValue(input); |
| 239 assembler.Branch(assembler.Float64Equal( | 213 Branch(Float64Equal(input_value, Float64Constant(0.0)), |
| 240 input_value, assembler.Float64Constant(0.0)), | 214 &if_inputiszero, &if_inputisnotzero); |
| 241 &if_inputiszero, &if_inputisnotzero); | 215 |
| 242 | 216 Bind(&if_inputiszero); |
| 243 assembler.Bind(&if_inputiszero); | 217 Return(SmiConstant(0)); |
| 244 assembler.Return(assembler.SmiConstant(0)); | 218 |
| 245 | 219 Bind(&if_inputisnotzero); |
| 246 assembler.Bind(&if_inputisnotzero); | 220 Return(input); |
| 247 assembler.Return(input); | 221 } |
| 248 } | 222 |
| 249 | 223 Bind(&if_inputisnotnumber); |
| 250 assembler.Bind(&if_inputisnotnumber); | |
| 251 { | 224 { |
| 252 // Need to convert the {input} to String first. | 225 // Need to convert the {input} to String first. |
| 253 // TODO(bmeurer): This could be more efficient if necessary. | 226 // TODO(bmeurer): This could be more efficient if necessary. |
| 254 Callable callable = CodeFactory::ToString(assembler.isolate()); | 227 Callable callable = CodeFactory::ToString(isolate()); |
| 255 var_input.Bind(assembler.CallStub(callable, context, input)); | 228 var_input.Bind(CallStub(callable, context, input)); |
| 256 assembler.Goto(&loop); | 229 Goto(&loop); |
| 257 } | 230 } |
| 258 } | 231 } |
| 259 } | 232 } |
| 260 } | 233 } |
| 261 } | 234 } |
| 262 | 235 |
| 263 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) | 236 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) |
| 264 void Builtins::Generate_NumberParseInt(compiler::CodeAssemblerState* state) { | 237 TF_BUILTIN(NumberParseInt, CodeStubAssembler) { |
| 265 typedef CodeStubAssembler::Label Label; | 238 Node* input = Parameter(1); |
| 266 typedef compiler::Node Node; | 239 Node* radix = Parameter(2); |
| 267 CodeStubAssembler assembler(state); | 240 Node* context = Parameter(5); |
| 268 | |
| 269 Node* input = assembler.Parameter(1); | |
| 270 Node* radix = assembler.Parameter(2); | |
| 271 Node* context = assembler.Parameter(5); | |
| 272 | 241 |
| 273 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). | 242 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). |
| 274 Label if_radix10(&assembler), if_generic(&assembler, Label::kDeferred); | 243 Label if_radix10(this), if_generic(this, Label::kDeferred); |
| 275 assembler.GotoIf(assembler.WordEqual(radix, assembler.UndefinedConstant()), | 244 GotoIf(WordEqual(radix, UndefinedConstant()), &if_radix10); |
| 276 &if_radix10); | 245 GotoIf(WordEqual(radix, SmiConstant(Smi::FromInt(10))), &if_radix10); |
| 277 assembler.GotoIf( | 246 GotoIf(WordEqual(radix, SmiConstant(Smi::FromInt(0))), &if_radix10); |
| 278 assembler.WordEqual(radix, assembler.SmiConstant(Smi::FromInt(10))), | 247 Goto(&if_generic); |
| 279 &if_radix10); | |
| 280 assembler.GotoIf( | |
| 281 assembler.WordEqual(radix, assembler.SmiConstant(Smi::FromInt(0))), | |
| 282 &if_radix10); | |
| 283 assembler.Goto(&if_generic); | |
| 284 | 248 |
| 285 assembler.Bind(&if_radix10); | 249 Bind(&if_radix10); |
| 286 { | 250 { |
| 287 // Check if we can avoid the ToString conversion on {input}. | 251 // Check if we can avoid the ToString conversion on {input}. |
| 288 Label if_inputissmi(&assembler), if_inputisheapnumber(&assembler), | 252 Label if_inputissmi(this), if_inputisheapnumber(this), |
| 289 if_inputisstring(&assembler); | 253 if_inputisstring(this); |
| 290 assembler.GotoIf(assembler.TaggedIsSmi(input), &if_inputissmi); | 254 GotoIf(TaggedIsSmi(input), &if_inputissmi); |
| 291 Node* input_map = assembler.LoadMap(input); | 255 Node* input_map = LoadMap(input); |
| 292 assembler.GotoIf( | 256 GotoIf(WordEqual(input_map, HeapNumberMapConstant()), |
| 293 assembler.WordEqual(input_map, assembler.HeapNumberMapConstant()), | 257 &if_inputisheapnumber); |
| 294 &if_inputisheapnumber); | 258 Node* input_instance_type = LoadMapInstanceType(input_map); |
| 295 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 259 Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, |
| 296 assembler.Branch(assembler.IsStringInstanceType(input_instance_type), | 260 &if_generic); |
| 297 &if_inputisstring, &if_generic); | |
| 298 | 261 |
| 299 assembler.Bind(&if_inputissmi); | 262 Bind(&if_inputissmi); |
| 300 { | 263 { |
| 301 // Just return the {input}. | 264 // Just return the {input}. |
| 302 assembler.Return(input); | 265 Return(input); |
| 303 } | 266 } |
| 304 | 267 |
| 305 assembler.Bind(&if_inputisheapnumber); | 268 Bind(&if_inputisheapnumber); |
| 306 { | 269 { |
| 307 // Check if the {input} value is in Signed32 range. | 270 // Check if the {input} value is in Signed32 range. |
| 308 Label if_inputissigned32(&assembler); | 271 Label if_inputissigned32(this); |
| 309 Node* input_value = assembler.LoadHeapNumberValue(input); | 272 Node* input_value = LoadHeapNumberValue(input); |
| 310 Node* input_value32 = assembler.TruncateFloat64ToWord32(input_value); | 273 Node* input_value32 = TruncateFloat64ToWord32(input_value); |
| 311 assembler.GotoIf( | 274 GotoIf(Float64Equal(input_value, ChangeInt32ToFloat64(input_value32)), |
| 312 assembler.Float64Equal(input_value, | 275 &if_inputissigned32); |
| 313 assembler.ChangeInt32ToFloat64(input_value32)), | |
| 314 &if_inputissigned32); | |
| 315 | 276 |
| 316 // Check if the absolute {input} value is in the ]0.01,1e9[ range. | 277 // Check if the absolute {input} value is in the ]0.01,1e9[ range. |
| 317 Node* input_value_abs = assembler.Float64Abs(input_value); | 278 Node* input_value_abs = Float64Abs(input_value); |
| 318 | 279 |
| 319 assembler.GotoUnless(assembler.Float64LessThan( | 280 GotoUnless(Float64LessThan(input_value_abs, Float64Constant(1e9)), |
| 320 input_value_abs, assembler.Float64Constant(1e9)), | 281 &if_generic); |
| 321 &if_generic); | 282 Branch(Float64LessThan(Float64Constant(0.01), input_value_abs), |
| 322 assembler.Branch(assembler.Float64LessThan( | 283 &if_inputissigned32, &if_generic); |
| 323 assembler.Float64Constant(0.01), input_value_abs), | |
| 324 &if_inputissigned32, &if_generic); | |
| 325 | 284 |
| 326 // Return the truncated int32 value, and return the tagged result. | 285 // Return the truncated int32 value, and return the tagged result. |
| 327 assembler.Bind(&if_inputissigned32); | 286 Bind(&if_inputissigned32); |
| 328 Node* result = assembler.ChangeInt32ToTagged(input_value32); | 287 Node* result = ChangeInt32ToTagged(input_value32); |
| 329 assembler.Return(result); | 288 Return(result); |
| 330 } | 289 } |
| 331 | 290 |
| 332 assembler.Bind(&if_inputisstring); | 291 Bind(&if_inputisstring); |
| 333 { | 292 { |
| 334 // Check if the String {input} has a cached array index. | 293 // Check if the String {input} has a cached array index. |
| 335 Node* input_hash = assembler.LoadNameHashField(input); | 294 Node* input_hash = LoadNameHashField(input); |
| 336 Node* input_bit = assembler.Word32And( | 295 Node* input_bit = Word32And( |
| 337 input_hash, | 296 input_hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
| 338 assembler.Int32Constant(String::kContainsCachedArrayIndexMask)); | 297 GotoIf(Word32NotEqual(input_bit, Int32Constant(0)), &if_generic); |
| 339 assembler.GotoIf( | |
| 340 assembler.Word32NotEqual(input_bit, assembler.Int32Constant(0)), | |
| 341 &if_generic); | |
| 342 | 298 |
| 343 // Return the cached array index as result. | 299 // Return the cached array index as result. |
| 344 Node* input_index = | 300 Node* input_index = |
| 345 assembler.DecodeWordFromWord32<String::ArrayIndexValueBits>( | 301 DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); |
| 346 input_hash); | 302 Node* result = SmiTag(input_index); |
| 347 Node* result = assembler.SmiTag(input_index); | 303 Return(result); |
| 348 assembler.Return(result); | |
| 349 } | 304 } |
| 350 } | 305 } |
| 351 | 306 |
| 352 assembler.Bind(&if_generic); | 307 Bind(&if_generic); |
| 353 { | 308 { |
| 354 Node* result = | 309 Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix); |
| 355 assembler.CallRuntime(Runtime::kStringParseInt, context, input, radix); | 310 Return(result); |
| 356 assembler.Return(result); | |
| 357 } | 311 } |
| 358 } | 312 } |
| 359 | 313 |
| 360 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) | 314 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) |
| 361 BUILTIN(NumberPrototypeToExponential) { | 315 BUILTIN(NumberPrototypeToExponential) { |
| 362 HandleScope scope(isolate); | 316 HandleScope scope(isolate); |
| 363 Handle<Object> value = args.at<Object>(0); | 317 Handle<Object> value = args.at<Object>(0); |
| 364 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | 318 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); |
| 365 | 319 |
| 366 // Unwrap the receiver {value}. | 320 // Unwrap the receiver {value}. |
| (...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1825 compiler::Node* lhs = assembler.Parameter(0); | 1779 compiler::Node* lhs = assembler.Parameter(0); |
| 1826 compiler::Node* rhs = assembler.Parameter(1); | 1780 compiler::Node* rhs = assembler.Parameter(1); |
| 1827 compiler::Node* context = assembler.Parameter(2); | 1781 compiler::Node* context = assembler.Parameter(2); |
| 1828 | 1782 |
| 1829 assembler.Return(assembler.StrictEqual(CodeStubAssembler::kNegateResult, lhs, | 1783 assembler.Return(assembler.StrictEqual(CodeStubAssembler::kNegateResult, lhs, |
| 1830 rhs, context)); | 1784 rhs, context)); |
| 1831 } | 1785 } |
| 1832 | 1786 |
| 1833 } // namespace internal | 1787 } // namespace internal |
| 1834 } // namespace v8 | 1788 } // namespace v8 |
| OLD | NEW |