| 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 #include "src/code-stub-assembler.h" |
| 9 #include "src/objects-inl.h" | 9 #include "src/objects-inl.h" |
| 10 | 10 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 | 13 |
| 14 class ConversionBuiltinsAssembler : public CodeStubAssembler { |
| 15 public: |
| 16 explicit ConversionBuiltinsAssembler(compiler::CodeAssemblerState* state) |
| 17 : CodeStubAssembler(state) {} |
| 18 |
| 19 protected: |
| 20 void Generate_NonPrimitiveToPrimitive(ToPrimitiveHint hint); |
| 21 |
| 22 void Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint); |
| 23 }; |
| 24 |
| 14 Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) { | 25 Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) { |
| 15 switch (hint) { | 26 switch (hint) { |
| 16 case ToPrimitiveHint::kDefault: | 27 case ToPrimitiveHint::kDefault: |
| 17 return NonPrimitiveToPrimitive_Default(); | 28 return NonPrimitiveToPrimitive_Default(); |
| 18 case ToPrimitiveHint::kNumber: | 29 case ToPrimitiveHint::kNumber: |
| 19 return NonPrimitiveToPrimitive_Number(); | 30 return NonPrimitiveToPrimitive_Number(); |
| 20 case ToPrimitiveHint::kString: | 31 case ToPrimitiveHint::kString: |
| 21 return NonPrimitiveToPrimitive_String(); | 32 return NonPrimitiveToPrimitive_String(); |
| 22 } | 33 } |
| 23 UNREACHABLE(); | 34 UNREACHABLE(); |
| 24 return Handle<Code>::null(); | 35 return Handle<Code>::null(); |
| 25 } | 36 } |
| 26 | 37 |
| 27 namespace { | |
| 28 | |
| 29 // ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) | 38 // ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) |
| 30 void Generate_NonPrimitiveToPrimitive(CodeStubAssembler* assembler, | 39 void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive( |
| 31 ToPrimitiveHint hint) { | 40 ToPrimitiveHint hint) { |
| 32 typedef CodeStubAssembler::Label Label; | 41 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 33 typedef compiler::Node Node; | 42 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 34 typedef TypeConversionDescriptor Descriptor; | |
| 35 | |
| 36 Node* input = assembler->Parameter(Descriptor::kArgument); | |
| 37 Node* context = assembler->Parameter(Descriptor::kContext); | |
| 38 | 43 |
| 39 // Lookup the @@toPrimitive property on the {input}. | 44 // Lookup the @@toPrimitive property on the {input}. |
| 40 Callable callable = CodeFactory::GetProperty(assembler->isolate()); | 45 Callable callable = CodeFactory::GetProperty(isolate()); |
| 41 Node* to_primitive_symbol = | 46 Node* to_primitive_symbol = HeapConstant(factory()->to_primitive_symbol()); |
| 42 assembler->HeapConstant(assembler->factory()->to_primitive_symbol()); | |
| 43 Node* exotic_to_prim = | 47 Node* exotic_to_prim = |
| 44 assembler->CallStub(callable, context, input, to_primitive_symbol); | 48 CallStub(callable, context, input, to_primitive_symbol); |
| 45 | 49 |
| 46 // Check if {exotic_to_prim} is neither null nor undefined. | 50 // Check if {exotic_to_prim} is neither null nor undefined. |
| 47 Label ordinary_to_primitive(assembler); | 51 Label ordinary_to_primitive(this); |
| 48 assembler->GotoIf( | 52 GotoIf(WordEqual(exotic_to_prim, NullConstant()), &ordinary_to_primitive); |
| 49 assembler->WordEqual(exotic_to_prim, assembler->NullConstant()), | 53 GotoIf(WordEqual(exotic_to_prim, UndefinedConstant()), |
| 50 &ordinary_to_primitive); | 54 &ordinary_to_primitive); |
| 51 assembler->GotoIf( | |
| 52 assembler->WordEqual(exotic_to_prim, assembler->UndefinedConstant()), | |
| 53 &ordinary_to_primitive); | |
| 54 { | 55 { |
| 55 // Invoke the {exotic_to_prim} method on the {input} with a string | 56 // Invoke the {exotic_to_prim} method on the {input} with a string |
| 56 // representation of the {hint}. | 57 // representation of the {hint}. |
| 57 Callable callable = CodeFactory::Call( | 58 Callable callable = |
| 58 assembler->isolate(), ConvertReceiverMode::kNotNullOrUndefined); | 59 CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined); |
| 59 Node* hint_string = assembler->HeapConstant( | 60 Node* hint_string = HeapConstant(factory()->ToPrimitiveHintString(hint)); |
| 60 assembler->factory()->ToPrimitiveHintString(hint)); | 61 Node* result = |
| 61 Node* result = assembler->CallJS(callable, context, exotic_to_prim, input, | 62 CallJS(callable, context, exotic_to_prim, input, hint_string); |
| 62 hint_string); | |
| 63 | 63 |
| 64 // Verify that the {result} is actually a primitive. | 64 // Verify that the {result} is actually a primitive. |
| 65 Label if_resultisprimitive(assembler), | 65 Label if_resultisprimitive(this), |
| 66 if_resultisnotprimitive(assembler, Label::kDeferred); | 66 if_resultisnotprimitive(this, Label::kDeferred); |
| 67 assembler->GotoIf(assembler->TaggedIsSmi(result), &if_resultisprimitive); | 67 GotoIf(TaggedIsSmi(result), &if_resultisprimitive); |
| 68 Node* result_instance_type = assembler->LoadInstanceType(result); | 68 Node* result_instance_type = LoadInstanceType(result); |
| 69 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); | 69 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); |
| 70 assembler->Branch(assembler->Int32LessThanOrEqual( | 70 Branch(Int32LessThanOrEqual(result_instance_type, |
| 71 result_instance_type, | 71 Int32Constant(LAST_PRIMITIVE_TYPE)), |
| 72 assembler->Int32Constant(LAST_PRIMITIVE_TYPE)), | 72 &if_resultisprimitive, &if_resultisnotprimitive); |
| 73 &if_resultisprimitive, &if_resultisnotprimitive); | |
| 74 | 73 |
| 75 assembler->Bind(&if_resultisprimitive); | 74 Bind(&if_resultisprimitive); |
| 76 { | 75 { |
| 77 // Just return the {result}. | 76 // Just return the {result}. |
| 78 assembler->Return(result); | 77 Return(result); |
| 79 } | 78 } |
| 80 | 79 |
| 81 assembler->Bind(&if_resultisnotprimitive); | 80 Bind(&if_resultisnotprimitive); |
| 82 { | 81 { |
| 83 // Somehow the @@toPrimitive method on {input} didn't yield a primitive. | 82 // Somehow the @@toPrimitive method on {input} didn't yield a primitive. |
| 84 assembler->TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, | 83 TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context); |
| 85 context); | |
| 86 } | 84 } |
| 87 } | 85 } |
| 88 | 86 |
| 89 // Convert using the OrdinaryToPrimitive algorithm instead. | 87 // Convert using the OrdinaryToPrimitive algorithm instead. |
| 90 assembler->Bind(&ordinary_to_primitive); | 88 Bind(&ordinary_to_primitive); |
| 91 { | 89 { |
| 92 Callable callable = CodeFactory::OrdinaryToPrimitive( | 90 Callable callable = CodeFactory::OrdinaryToPrimitive( |
| 93 assembler->isolate(), (hint == ToPrimitiveHint::kString) | 91 isolate(), (hint == ToPrimitiveHint::kString) |
| 94 ? OrdinaryToPrimitiveHint::kString | 92 ? OrdinaryToPrimitiveHint::kString |
| 95 : OrdinaryToPrimitiveHint::kNumber); | 93 : OrdinaryToPrimitiveHint::kNumber); |
| 96 assembler->TailCallStub(callable, context, input); | 94 TailCallStub(callable, context, input); |
| 97 } | 95 } |
| 98 } | 96 } |
| 99 | 97 |
| 100 } // namespace | 98 TF_BUILTIN(NonPrimitiveToPrimitive_Default, ConversionBuiltinsAssembler) { |
| 101 | 99 Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kDefault); |
| 102 void Builtins::Generate_NonPrimitiveToPrimitive_Default( | |
| 103 compiler::CodeAssemblerState* state) { | |
| 104 CodeStubAssembler assembler(state); | |
| 105 Generate_NonPrimitiveToPrimitive(&assembler, ToPrimitiveHint::kDefault); | |
| 106 } | 100 } |
| 107 | 101 |
| 108 void Builtins::Generate_NonPrimitiveToPrimitive_Number( | 102 TF_BUILTIN(NonPrimitiveToPrimitive_Number, ConversionBuiltinsAssembler) { |
| 109 compiler::CodeAssemblerState* state) { | 103 Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kNumber); |
| 110 CodeStubAssembler assembler(state); | |
| 111 Generate_NonPrimitiveToPrimitive(&assembler, ToPrimitiveHint::kNumber); | |
| 112 } | 104 } |
| 113 | 105 |
| 114 void Builtins::Generate_NonPrimitiveToPrimitive_String( | 106 TF_BUILTIN(NonPrimitiveToPrimitive_String, ConversionBuiltinsAssembler) { |
| 115 compiler::CodeAssemblerState* state) { | 107 Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kString); |
| 116 CodeStubAssembler assembler(state); | |
| 117 Generate_NonPrimitiveToPrimitive(&assembler, ToPrimitiveHint::kString); | |
| 118 } | 108 } |
| 119 | 109 |
| 120 void Builtins::Generate_StringToNumber(compiler::CodeAssemblerState* state) { | 110 TF_BUILTIN(StringToNumber, CodeStubAssembler) { |
| 121 typedef compiler::Node Node; | 111 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 122 typedef TypeConversionDescriptor Descriptor; | 112 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 123 CodeStubAssembler assembler(state); | |
| 124 | 113 |
| 125 Node* input = assembler.Parameter(Descriptor::kArgument); | 114 Return(StringToNumber(context, input)); |
| 126 Node* context = assembler.Parameter(Descriptor::kContext); | |
| 127 | |
| 128 assembler.Return(assembler.StringToNumber(context, input)); | |
| 129 } | 115 } |
| 130 | 116 |
| 131 void Builtins::Generate_ToName(compiler::CodeAssemblerState* state) { | 117 TF_BUILTIN(ToName, CodeStubAssembler) { |
| 132 typedef compiler::Node Node; | 118 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 133 typedef TypeConversionDescriptor Descriptor; | 119 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 134 CodeStubAssembler assembler(state); | |
| 135 | 120 |
| 136 Node* input = assembler.Parameter(Descriptor::kArgument); | 121 Return(ToName(context, input)); |
| 137 Node* context = assembler.Parameter(Descriptor::kContext); | |
| 138 | |
| 139 assembler.Return(assembler.ToName(context, input)); | |
| 140 } | 122 } |
| 141 | 123 |
| 142 // static | 124 TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) { |
| 143 void Builtins::Generate_NonNumberToNumber(compiler::CodeAssemblerState* state) { | 125 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 144 typedef compiler::Node Node; | 126 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 145 typedef TypeConversionDescriptor Descriptor; | |
| 146 CodeStubAssembler assembler(state); | |
| 147 | 127 |
| 148 Node* input = assembler.Parameter(Descriptor::kArgument); | 128 Return(NonNumberToNumber(context, input)); |
| 149 Node* context = assembler.Parameter(Descriptor::kContext); | |
| 150 | |
| 151 assembler.Return(assembler.NonNumberToNumber(context, input)); | |
| 152 } | 129 } |
| 153 | 130 |
| 154 // ES6 section 7.1.3 ToNumber ( argument ) | 131 // ES6 section 7.1.3 ToNumber ( argument ) |
| 155 void Builtins::Generate_ToNumber(compiler::CodeAssemblerState* state) { | 132 TF_BUILTIN(ToNumber, CodeStubAssembler) { |
| 156 typedef compiler::Node Node; | 133 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 157 typedef TypeConversionDescriptor Descriptor; | 134 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 158 CodeStubAssembler assembler(state); | |
| 159 | 135 |
| 160 Node* input = assembler.Parameter(Descriptor::kArgument); | 136 Return(ToNumber(context, input)); |
| 161 Node* context = assembler.Parameter(Descriptor::kContext); | |
| 162 | |
| 163 assembler.Return(assembler.ToNumber(context, input)); | |
| 164 } | 137 } |
| 165 | 138 |
| 166 void Builtins::Generate_ToString(compiler::CodeAssemblerState* state) { | 139 TF_BUILTIN(ToString, CodeStubAssembler) { |
| 167 typedef CodeStubAssembler::Label Label; | 140 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 168 typedef compiler::Node Node; | 141 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 169 typedef TypeConversionDescriptor Descriptor; | |
| 170 CodeStubAssembler assembler(state); | |
| 171 | 142 |
| 172 Node* input = assembler.Parameter(Descriptor::kArgument); | 143 Label is_number(this); |
| 173 Node* context = assembler.Parameter(Descriptor::kContext); | 144 Label runtime(this); |
| 174 | 145 |
| 175 Label is_number(&assembler); | 146 GotoIf(TaggedIsSmi(input), &is_number); |
| 176 Label runtime(&assembler); | |
| 177 | 147 |
| 178 assembler.GotoIf(assembler.TaggedIsSmi(input), &is_number); | 148 Node* input_map = LoadMap(input); |
| 149 Node* input_instance_type = LoadMapInstanceType(input_map); |
| 179 | 150 |
| 180 Node* input_map = assembler.LoadMap(input); | 151 Label not_string(this); |
| 181 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 152 GotoIfNot(IsStringInstanceType(input_instance_type), ¬_string); |
| 153 Return(input); |
| 182 | 154 |
| 183 Label not_string(&assembler); | 155 Label not_heap_number(this); |
| 184 assembler.GotoIfNot(assembler.IsStringInstanceType(input_instance_type), | |
| 185 ¬_string); | |
| 186 assembler.Return(input); | |
| 187 | 156 |
| 188 Label not_heap_number(&assembler); | 157 Bind(¬_string); |
| 158 { Branch(IsHeapNumberMap(input_map), &is_number, ¬_heap_number); } |
| 189 | 159 |
| 190 assembler.Bind(¬_string); | 160 Bind(&is_number); |
| 161 { Return(NumberToString(context, input)); } |
| 162 |
| 163 Bind(¬_heap_number); |
| 191 { | 164 { |
| 192 assembler.GotoIfNot(assembler.IsHeapNumberMap(input_map), ¬_heap_number); | 165 GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)), |
| 193 assembler.Goto(&is_number); | 166 &runtime); |
| 167 Return(LoadObjectField(input, Oddball::kToStringOffset)); |
| 194 } | 168 } |
| 195 | 169 |
| 196 assembler.Bind(&is_number); | 170 Bind(&runtime); |
| 197 { assembler.Return(assembler.NumberToString(context, input)); } | 171 { Return(CallRuntime(Runtime::kToString, context, input)); } |
| 198 | |
| 199 assembler.Bind(¬_heap_number); | |
| 200 { | |
| 201 assembler.GotoIf( | |
| 202 assembler.Word32NotEqual(input_instance_type, | |
| 203 assembler.Int32Constant(ODDBALL_TYPE)), | |
| 204 &runtime); | |
| 205 assembler.Return( | |
| 206 assembler.LoadObjectField(input, Oddball::kToStringOffset)); | |
| 207 } | |
| 208 | |
| 209 assembler.Bind(&runtime); | |
| 210 { | |
| 211 assembler.Return(assembler.CallRuntime(Runtime::kToString, context, input)); | |
| 212 } | |
| 213 } | 172 } |
| 214 | 173 |
| 215 Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) { | 174 Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) { |
| 216 switch (hint) { | 175 switch (hint) { |
| 217 case OrdinaryToPrimitiveHint::kNumber: | 176 case OrdinaryToPrimitiveHint::kNumber: |
| 218 return OrdinaryToPrimitive_Number(); | 177 return OrdinaryToPrimitive_Number(); |
| 219 case OrdinaryToPrimitiveHint::kString: | 178 case OrdinaryToPrimitiveHint::kString: |
| 220 return OrdinaryToPrimitive_String(); | 179 return OrdinaryToPrimitive_String(); |
| 221 } | 180 } |
| 222 UNREACHABLE(); | 181 UNREACHABLE(); |
| 223 return Handle<Code>::null(); | 182 return Handle<Code>::null(); |
| 224 } | 183 } |
| 225 | 184 |
| 226 namespace { | |
| 227 | |
| 228 // 7.1.1.1 OrdinaryToPrimitive ( O, hint ) | 185 // 7.1.1.1 OrdinaryToPrimitive ( O, hint ) |
| 229 void Generate_OrdinaryToPrimitive(CodeStubAssembler* assembler, | 186 void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive( |
| 230 OrdinaryToPrimitiveHint hint) { | 187 OrdinaryToPrimitiveHint hint) { |
| 231 typedef CodeStubAssembler::Label Label; | 188 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 232 typedef compiler::Node Node; | 189 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 233 typedef CodeStubAssembler::Variable Variable; | 190 |
| 234 typedef TypeConversionDescriptor Descriptor; | 191 Variable var_result(this, MachineRepresentation::kTagged); |
| 235 | 192 Label return_result(this, &var_result); |
| 236 Node* input = assembler->Parameter(Descriptor::kArgument); | |
| 237 Node* context = assembler->Parameter(Descriptor::kContext); | |
| 238 | |
| 239 Variable var_result(assembler, MachineRepresentation::kTagged); | |
| 240 Label return_result(assembler, &var_result); | |
| 241 | 193 |
| 242 Handle<String> method_names[2]; | 194 Handle<String> method_names[2]; |
| 243 switch (hint) { | 195 switch (hint) { |
| 244 case OrdinaryToPrimitiveHint::kNumber: | 196 case OrdinaryToPrimitiveHint::kNumber: |
| 245 method_names[0] = assembler->factory()->valueOf_string(); | 197 method_names[0] = factory()->valueOf_string(); |
| 246 method_names[1] = assembler->factory()->toString_string(); | 198 method_names[1] = factory()->toString_string(); |
| 247 break; | 199 break; |
| 248 case OrdinaryToPrimitiveHint::kString: | 200 case OrdinaryToPrimitiveHint::kString: |
| 249 method_names[0] = assembler->factory()->toString_string(); | 201 method_names[0] = factory()->toString_string(); |
| 250 method_names[1] = assembler->factory()->valueOf_string(); | 202 method_names[1] = factory()->valueOf_string(); |
| 251 break; | 203 break; |
| 252 } | 204 } |
| 253 for (Handle<String> name : method_names) { | 205 for (Handle<String> name : method_names) { |
| 254 // Lookup the {name} on the {input}. | 206 // Lookup the {name} on the {input}. |
| 255 Callable callable = CodeFactory::GetProperty(assembler->isolate()); | 207 Callable callable = CodeFactory::GetProperty(isolate()); |
| 256 Node* name_string = assembler->HeapConstant(name); | 208 Node* name_string = HeapConstant(name); |
| 257 Node* method = assembler->CallStub(callable, context, input, name_string); | 209 Node* method = CallStub(callable, context, input, name_string); |
| 258 | 210 |
| 259 // Check if the {method} is callable. | 211 // Check if the {method} is callable. |
| 260 Label if_methodiscallable(assembler), | 212 Label if_methodiscallable(this), |
| 261 if_methodisnotcallable(assembler, Label::kDeferred); | 213 if_methodisnotcallable(this, Label::kDeferred); |
| 262 assembler->GotoIf(assembler->TaggedIsSmi(method), &if_methodisnotcallable); | 214 GotoIf(TaggedIsSmi(method), &if_methodisnotcallable); |
| 263 Node* method_map = assembler->LoadMap(method); | 215 Node* method_map = LoadMap(method); |
| 264 assembler->Branch(assembler->IsCallableMap(method_map), | 216 Branch(IsCallableMap(method_map), &if_methodiscallable, |
| 265 &if_methodiscallable, &if_methodisnotcallable); | 217 &if_methodisnotcallable); |
| 266 | 218 |
| 267 assembler->Bind(&if_methodiscallable); | 219 Bind(&if_methodiscallable); |
| 268 { | 220 { |
| 269 // Call the {method} on the {input}. | 221 // Call the {method} on the {input}. |
| 270 Callable callable = CodeFactory::Call( | 222 Callable callable = CodeFactory::Call( |
| 271 assembler->isolate(), ConvertReceiverMode::kNotNullOrUndefined); | 223 isolate(), ConvertReceiverMode::kNotNullOrUndefined); |
| 272 Node* result = assembler->CallJS(callable, context, method, input); | 224 Node* result = CallJS(callable, context, method, input); |
| 273 var_result.Bind(result); | 225 var_result.Bind(result); |
| 274 | 226 |
| 275 // Return the {result} if it is a primitive. | 227 // Return the {result} if it is a primitive. |
| 276 assembler->GotoIf(assembler->TaggedIsSmi(result), &return_result); | 228 GotoIf(TaggedIsSmi(result), &return_result); |
| 277 Node* result_instance_type = assembler->LoadInstanceType(result); | 229 Node* result_instance_type = LoadInstanceType(result); |
| 278 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); | 230 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE); |
| 279 assembler->GotoIf(assembler->Int32LessThanOrEqual( | 231 GotoIf(Int32LessThanOrEqual(result_instance_type, |
| 280 result_instance_type, | 232 Int32Constant(LAST_PRIMITIVE_TYPE)), |
| 281 assembler->Int32Constant(LAST_PRIMITIVE_TYPE)), | 233 &return_result); |
| 282 &return_result); | |
| 283 } | 234 } |
| 284 | 235 |
| 285 // Just continue with the next {name} if the {method} is not callable. | 236 // Just continue with the next {name} if the {method} is not callable. |
| 286 assembler->Goto(&if_methodisnotcallable); | 237 Goto(&if_methodisnotcallable); |
| 287 assembler->Bind(&if_methodisnotcallable); | 238 Bind(&if_methodisnotcallable); |
| 288 } | 239 } |
| 289 | 240 |
| 290 assembler->TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context); | 241 TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context); |
| 291 | 242 |
| 292 assembler->Bind(&return_result); | 243 Bind(&return_result); |
| 293 assembler->Return(var_result.value()); | 244 Return(var_result.value()); |
| 294 } | 245 } |
| 295 | 246 |
| 296 } // namespace | 247 TF_BUILTIN(OrdinaryToPrimitive_Number, ConversionBuiltinsAssembler) { |
| 297 | 248 Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint::kNumber); |
| 298 void Builtins::Generate_OrdinaryToPrimitive_Number( | 249 } |
| 299 compiler::CodeAssemblerState* state) { | 250 |
| 300 CodeStubAssembler assembler(state); | 251 TF_BUILTIN(OrdinaryToPrimitive_String, ConversionBuiltinsAssembler) { |
| 301 Generate_OrdinaryToPrimitive(&assembler, OrdinaryToPrimitiveHint::kNumber); | 252 Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint::kString); |
| 302 } | |
| 303 | |
| 304 void Builtins::Generate_OrdinaryToPrimitive_String( | |
| 305 compiler::CodeAssemblerState* state) { | |
| 306 CodeStubAssembler assembler(state); | |
| 307 Generate_OrdinaryToPrimitive(&assembler, OrdinaryToPrimitiveHint::kString); | |
| 308 } | 253 } |
| 309 | 254 |
| 310 // ES6 section 7.1.2 ToBoolean ( argument ) | 255 // ES6 section 7.1.2 ToBoolean ( argument ) |
| 311 void Builtins::Generate_ToBoolean(compiler::CodeAssemblerState* state) { | 256 TF_BUILTIN(ToBoolean, CodeStubAssembler) { |
| 312 typedef compiler::Node Node; | 257 Node* value = Parameter(TypeConversionDescriptor::kArgument); |
| 313 typedef CodeStubAssembler::Label Label; | 258 |
| 314 typedef TypeConversionDescriptor Descriptor; | 259 Label return_true(this), return_false(this); |
| 315 CodeStubAssembler assembler(state); | 260 BranchIfToBooleanIsTrue(value, &return_true, &return_false); |
| 316 | 261 |
| 317 Node* value = assembler.Parameter(Descriptor::kArgument); | 262 Bind(&return_true); |
| 318 | 263 Return(BooleanConstant(true)); |
| 319 Label return_true(&assembler), return_false(&assembler); | 264 |
| 320 assembler.BranchIfToBooleanIsTrue(value, &return_true, &return_false); | 265 Bind(&return_false); |
| 321 | 266 Return(BooleanConstant(false)); |
| 322 assembler.Bind(&return_true); | 267 } |
| 323 assembler.Return(assembler.BooleanConstant(true)); | 268 |
| 324 | 269 TF_BUILTIN(ToLength, CodeStubAssembler) { |
| 325 assembler.Bind(&return_false); | 270 Node* context = Parameter(1); |
| 326 assembler.Return(assembler.BooleanConstant(false)); | |
| 327 } | |
| 328 | |
| 329 void Builtins::Generate_ToLength(compiler::CodeAssemblerState* state) { | |
| 330 typedef CodeStubAssembler::Label Label; | |
| 331 typedef compiler::Node Node; | |
| 332 typedef CodeStubAssembler::Variable Variable; | |
| 333 CodeStubAssembler assembler(state); | |
| 334 | |
| 335 Node* context = assembler.Parameter(1); | |
| 336 | 271 |
| 337 // We might need to loop once for ToNumber conversion. | 272 // We might need to loop once for ToNumber conversion. |
| 338 Variable var_len(&assembler, MachineRepresentation::kTagged); | 273 Variable var_len(this, MachineRepresentation::kTagged, Parameter(0)); |
| 339 Label loop(&assembler, &var_len); | 274 Label loop(this, &var_len); |
| 340 var_len.Bind(assembler.Parameter(0)); | 275 Goto(&loop); |
| 341 assembler.Goto(&loop); | 276 Bind(&loop); |
| 342 assembler.Bind(&loop); | |
| 343 { | 277 { |
| 344 // Shared entry points. | 278 // Shared entry points. |
| 345 Label return_len(&assembler), | 279 Label return_len(this), return_two53minus1(this, Label::kDeferred), |
| 346 return_two53minus1(&assembler, Label::kDeferred), | 280 return_zero(this, Label::kDeferred); |
| 347 return_zero(&assembler, Label::kDeferred); | |
| 348 | 281 |
| 349 // Load the current {len} value. | 282 // Load the current {len} value. |
| 350 Node* len = var_len.value(); | 283 Node* len = var_len.value(); |
| 351 | 284 |
| 352 // Check if {len} is a positive Smi. | 285 // Check if {len} is a positive Smi. |
| 353 assembler.GotoIf(assembler.TaggedIsPositiveSmi(len), &return_len); | 286 GotoIf(TaggedIsPositiveSmi(len), &return_len); |
| 354 | 287 |
| 355 // Check if {len} is a (negative) Smi. | 288 // Check if {len} is a (negative) Smi. |
| 356 assembler.GotoIf(assembler.TaggedIsSmi(len), &return_zero); | 289 GotoIf(TaggedIsSmi(len), &return_zero); |
| 357 | 290 |
| 358 // Check if {len} is a HeapNumber. | 291 // Check if {len} is a HeapNumber. |
| 359 Label if_lenisheapnumber(&assembler), | 292 Label if_lenisheapnumber(this), |
| 360 if_lenisnotheapnumber(&assembler, Label::kDeferred); | 293 if_lenisnotheapnumber(this, Label::kDeferred); |
| 361 assembler.Branch(assembler.IsHeapNumberMap(assembler.LoadMap(len)), | 294 Branch(IsHeapNumberMap(LoadMap(len)), &if_lenisheapnumber, |
| 362 &if_lenisheapnumber, &if_lenisnotheapnumber); | 295 &if_lenisnotheapnumber); |
| 363 | 296 |
| 364 assembler.Bind(&if_lenisheapnumber); | 297 Bind(&if_lenisheapnumber); |
| 365 { | 298 { |
| 366 // Load the floating-point value of {len}. | 299 // Load the floating-point value of {len}. |
| 367 Node* len_value = assembler.LoadHeapNumberValue(len); | 300 Node* len_value = LoadHeapNumberValue(len); |
| 368 | 301 |
| 369 // Check if {len} is not greater than zero. | 302 // Check if {len} is not greater than zero. |
| 370 assembler.GotoIfNot(assembler.Float64GreaterThan( | 303 GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)), |
| 371 len_value, assembler.Float64Constant(0.0)), | 304 &return_zero); |
| 372 &return_zero); | |
| 373 | 305 |
| 374 // Check if {len} is greater than or equal to 2^53-1. | 306 // Check if {len} is greater than or equal to 2^53-1. |
| 375 assembler.GotoIf( | 307 GotoIf(Float64GreaterThanOrEqual(len_value, |
| 376 assembler.Float64GreaterThanOrEqual( | 308 Float64Constant(kMaxSafeInteger)), |
| 377 len_value, assembler.Float64Constant(kMaxSafeInteger)), | 309 &return_two53minus1); |
| 378 &return_two53minus1); | |
| 379 | 310 |
| 380 // Round the {len} towards -Infinity. | 311 // Round the {len} towards -Infinity. |
| 381 Node* value = assembler.Float64Floor(len_value); | 312 Node* value = Float64Floor(len_value); |
| 382 Node* result = assembler.ChangeFloat64ToTagged(value); | 313 Node* result = ChangeFloat64ToTagged(value); |
| 383 assembler.Return(result); | 314 Return(result); |
| 384 } | 315 } |
| 385 | 316 |
| 386 assembler.Bind(&if_lenisnotheapnumber); | 317 Bind(&if_lenisnotheapnumber); |
| 387 { | 318 { |
| 388 // Need to convert {len} to a Number first. | 319 // Need to convert {len} to a Number first. |
| 389 Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); | 320 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
| 390 var_len.Bind(assembler.CallStub(callable, context, len)); | 321 var_len.Bind(CallStub(callable, context, len)); |
| 391 assembler.Goto(&loop); | 322 Goto(&loop); |
| 392 } | 323 } |
| 393 | 324 |
| 394 assembler.Bind(&return_len); | 325 Bind(&return_len); |
| 395 assembler.Return(var_len.value()); | 326 Return(var_len.value()); |
| 396 | 327 |
| 397 assembler.Bind(&return_two53minus1); | 328 Bind(&return_two53minus1); |
| 398 assembler.Return(assembler.NumberConstant(kMaxSafeInteger)); | 329 Return(NumberConstant(kMaxSafeInteger)); |
| 399 | 330 |
| 400 assembler.Bind(&return_zero); | 331 Bind(&return_zero); |
| 401 assembler.Return(assembler.SmiConstant(Smi::kZero)); | 332 Return(SmiConstant(Smi::kZero)); |
| 402 } | 333 } |
| 403 } | 334 } |
| 404 | 335 |
| 405 void Builtins::Generate_ToInteger(compiler::CodeAssemblerState* state) { | 336 TF_BUILTIN(ToInteger, CodeStubAssembler) { |
| 406 typedef TypeConversionDescriptor Descriptor; | 337 Node* input = Parameter(TypeConversionDescriptor::kArgument); |
| 407 CodeStubAssembler assembler(state); | 338 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 408 | 339 |
| 409 compiler::Node* input = assembler.Parameter(Descriptor::kArgument); | 340 Return(ToInteger(context, input)); |
| 410 compiler::Node* context = assembler.Parameter(Descriptor::kContext); | |
| 411 | |
| 412 assembler.Return(assembler.ToInteger(context, input)); | |
| 413 } | 341 } |
| 414 | 342 |
| 415 // ES6 section 7.1.13 ToObject (argument) | 343 // ES6 section 7.1.13 ToObject (argument) |
| 416 void Builtins::Generate_ToObject(compiler::CodeAssemblerState* state) { | 344 TF_BUILTIN(ToObject, CodeStubAssembler) { |
| 417 typedef compiler::Node Node; | 345 Label if_number(this, Label::kDeferred), if_notsmi(this), if_jsreceiver(this), |
| 418 typedef CodeStubAssembler::Label Label; | 346 if_noconstructor(this, Label::kDeferred), if_wrapjsvalue(this); |
| 419 typedef CodeStubAssembler::Variable Variable; | 347 |
| 420 typedef TypeConversionDescriptor Descriptor; | 348 Node* object = Parameter(TypeConversionDescriptor::kArgument); |
| 421 CodeStubAssembler assembler(state); | 349 Node* context = Parameter(TypeConversionDescriptor::kContext); |
| 422 | 350 |
| 423 Label if_number(&assembler, Label::kDeferred), if_notsmi(&assembler), | 351 Variable constructor_function_index_var(this, |
| 424 if_jsreceiver(&assembler), if_noconstructor(&assembler, Label::kDeferred), | |
| 425 if_wrapjsvalue(&assembler); | |
| 426 | |
| 427 Node* object = assembler.Parameter(Descriptor::kArgument); | |
| 428 Node* context = assembler.Parameter(Descriptor::kContext); | |
| 429 | |
| 430 Variable constructor_function_index_var(&assembler, | |
| 431 MachineType::PointerRepresentation()); | 352 MachineType::PointerRepresentation()); |
| 432 | 353 |
| 433 assembler.Branch(assembler.TaggedIsSmi(object), &if_number, &if_notsmi); | 354 Branch(TaggedIsSmi(object), &if_number, &if_notsmi); |
| 434 | 355 |
| 435 assembler.Bind(&if_notsmi); | 356 Bind(&if_notsmi); |
| 436 Node* map = assembler.LoadMap(object); | 357 Node* map = LoadMap(object); |
| 437 | 358 |
| 438 assembler.GotoIf(assembler.IsHeapNumberMap(map), &if_number); | 359 GotoIf(IsHeapNumberMap(map), &if_number); |
| 439 | 360 |
| 440 Node* instance_type = assembler.LoadMapInstanceType(map); | 361 Node* instance_type = LoadMapInstanceType(map); |
| 441 assembler.GotoIf(assembler.IsJSReceiverInstanceType(instance_type), | 362 GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver); |
| 442 &if_jsreceiver); | 363 |
| 443 | 364 Node* constructor_function_index = LoadMapConstructorFunctionIndex(map); |
| 444 Node* constructor_function_index = | 365 GotoIf(WordEqual(constructor_function_index, |
| 445 assembler.LoadMapConstructorFunctionIndex(map); | 366 IntPtrConstant(Map::kNoConstructorFunctionIndex)), |
| 446 assembler.GotoIf(assembler.WordEqual(constructor_function_index, | 367 &if_noconstructor); |
| 447 assembler.IntPtrConstant( | |
| 448 Map::kNoConstructorFunctionIndex)), | |
| 449 &if_noconstructor); | |
| 450 constructor_function_index_var.Bind(constructor_function_index); | 368 constructor_function_index_var.Bind(constructor_function_index); |
| 451 assembler.Goto(&if_wrapjsvalue); | 369 Goto(&if_wrapjsvalue); |
| 452 | 370 |
| 453 assembler.Bind(&if_number); | 371 Bind(&if_number); |
| 454 constructor_function_index_var.Bind( | 372 constructor_function_index_var.Bind( |
| 455 assembler.IntPtrConstant(Context::NUMBER_FUNCTION_INDEX)); | 373 IntPtrConstant(Context::NUMBER_FUNCTION_INDEX)); |
| 456 assembler.Goto(&if_wrapjsvalue); | 374 Goto(&if_wrapjsvalue); |
| 457 | 375 |
| 458 assembler.Bind(&if_wrapjsvalue); | 376 Bind(&if_wrapjsvalue); |
| 459 Node* native_context = assembler.LoadNativeContext(context); | 377 Node* native_context = LoadNativeContext(context); |
| 460 Node* constructor = assembler.LoadFixedArrayElement( | 378 Node* constructor = LoadFixedArrayElement( |
| 461 native_context, constructor_function_index_var.value()); | 379 native_context, constructor_function_index_var.value()); |
| 462 Node* initial_map = assembler.LoadObjectField( | 380 Node* initial_map = |
| 463 constructor, JSFunction::kPrototypeOrInitialMapOffset); | 381 LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset); |
| 464 Node* js_value = assembler.Allocate(JSValue::kSize); | 382 Node* js_value = Allocate(JSValue::kSize); |
| 465 assembler.StoreMapNoWriteBarrier(js_value, initial_map); | 383 StoreMapNoWriteBarrier(js_value, initial_map); |
| 466 assembler.StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset, | 384 StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset, |
| 467 Heap::kEmptyFixedArrayRootIndex); | 385 Heap::kEmptyFixedArrayRootIndex); |
| 468 assembler.StoreObjectFieldRoot(js_value, JSObject::kElementsOffset, | 386 StoreObjectFieldRoot(js_value, JSObject::kElementsOffset, |
| 469 Heap::kEmptyFixedArrayRootIndex); | 387 Heap::kEmptyFixedArrayRootIndex); |
| 470 assembler.StoreObjectField(js_value, JSValue::kValueOffset, object); | 388 StoreObjectField(js_value, JSValue::kValueOffset, object); |
| 471 assembler.Return(js_value); | 389 Return(js_value); |
| 472 | 390 |
| 473 assembler.Bind(&if_noconstructor); | 391 Bind(&if_noconstructor); |
| 474 assembler.TailCallRuntime( | 392 TailCallRuntime( |
| 475 Runtime::kThrowUndefinedOrNullToObject, context, | 393 Runtime::kThrowUndefinedOrNullToObject, context, |
| 476 assembler.HeapConstant( | 394 HeapConstant(factory()->NewStringFromAsciiChecked("ToObject", TENURED))); |
| 477 assembler.factory()->NewStringFromAsciiChecked("ToObject", TENURED))); | 395 |
| 478 | 396 Bind(&if_jsreceiver); |
| 479 assembler.Bind(&if_jsreceiver); | 397 Return(object); |
| 480 assembler.Return(object); | |
| 481 } | 398 } |
| 482 | 399 |
| 483 // Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf). | 400 // Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf). |
| 484 void Builtins::Generate_ClassOf(compiler::CodeAssemblerState* state) { | 401 TF_BUILTIN(ClassOf, CodeStubAssembler) { |
| 485 typedef compiler::Node Node; | 402 Node* object = Parameter(TypeofDescriptor::kObject); |
| 486 typedef TypeofDescriptor Descriptor; | 403 |
| 487 CodeStubAssembler assembler(state); | 404 Return(ClassOf(object)); |
| 488 | |
| 489 Node* object = assembler.Parameter(Descriptor::kObject); | |
| 490 | |
| 491 assembler.Return(assembler.ClassOf(object)); | |
| 492 } | 405 } |
| 493 | 406 |
| 494 // ES6 section 12.5.5 typeof operator | 407 // ES6 section 12.5.5 typeof operator |
| 495 void Builtins::Generate_Typeof(compiler::CodeAssemblerState* state) { | 408 TF_BUILTIN(Typeof, CodeStubAssembler) { |
| 496 typedef compiler::Node Node; | 409 Node* object = Parameter(TypeofDescriptor::kObject); |
| 497 typedef TypeofDescriptor Descriptor; | 410 Node* context = Parameter(TypeofDescriptor::kContext); |
| 498 CodeStubAssembler assembler(state); | 411 |
| 499 | 412 Return(Typeof(object, context)); |
| 500 Node* object = assembler.Parameter(Descriptor::kObject); | |
| 501 Node* context = assembler.Parameter(Descriptor::kContext); | |
| 502 | |
| 503 assembler.Return(assembler.Typeof(object, context)); | |
| 504 } | 413 } |
| 505 | 414 |
| 506 } // namespace internal | 415 } // namespace internal |
| 507 } // namespace v8 | 416 } // namespace v8 |
| OLD | NEW |