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 |