Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: src/builtins/builtins-conversion.cc

Issue 2752143004: [refactor] Separate generated builtins and C++ builtins into separate files (Closed)
Patch Set: tentative gcmole fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-constructor-gen.cc ('k') | src/builtins/builtins-conversion-gen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "src/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h"
7 #include "src/code-factory.h"
8 #include "src/code-stub-assembler.h"
9 #include "src/objects-inl.h"
10
11 namespace v8 {
12 namespace internal {
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
25 Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
26 switch (hint) {
27 case ToPrimitiveHint::kDefault:
28 return NonPrimitiveToPrimitive_Default();
29 case ToPrimitiveHint::kNumber:
30 return NonPrimitiveToPrimitive_Number();
31 case ToPrimitiveHint::kString:
32 return NonPrimitiveToPrimitive_String();
33 }
34 UNREACHABLE();
35 return Handle<Code>::null();
36 }
37
38 // ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
39 void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
40 ToPrimitiveHint hint) {
41 Node* input = Parameter(TypeConversionDescriptor::kArgument);
42 Node* context = Parameter(TypeConversionDescriptor::kContext);
43
44 // Lookup the @@toPrimitive property on the {input}.
45 Node* exotic_to_prim =
46 GetProperty(context, input, factory()->to_primitive_symbol());
47
48 // Check if {exotic_to_prim} is neither null nor undefined.
49 Label ordinary_to_primitive(this);
50 GotoIf(WordEqual(exotic_to_prim, NullConstant()), &ordinary_to_primitive);
51 GotoIf(WordEqual(exotic_to_prim, UndefinedConstant()),
52 &ordinary_to_primitive);
53 {
54 // Invoke the {exotic_to_prim} method on the {input} with a string
55 // representation of the {hint}.
56 Callable callable =
57 CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined);
58 Node* hint_string = HeapConstant(factory()->ToPrimitiveHintString(hint));
59 Node* result =
60 CallJS(callable, context, exotic_to_prim, input, hint_string);
61
62 // Verify that the {result} is actually a primitive.
63 Label if_resultisprimitive(this),
64 if_resultisnotprimitive(this, Label::kDeferred);
65 GotoIf(TaggedIsSmi(result), &if_resultisprimitive);
66 Node* result_instance_type = LoadInstanceType(result);
67 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
68 Branch(Int32LessThanOrEqual(result_instance_type,
69 Int32Constant(LAST_PRIMITIVE_TYPE)),
70 &if_resultisprimitive, &if_resultisnotprimitive);
71
72 Bind(&if_resultisprimitive);
73 {
74 // Just return the {result}.
75 Return(result);
76 }
77
78 Bind(&if_resultisnotprimitive);
79 {
80 // Somehow the @@toPrimitive method on {input} didn't yield a primitive.
81 TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
82 }
83 }
84
85 // Convert using the OrdinaryToPrimitive algorithm instead.
86 Bind(&ordinary_to_primitive);
87 {
88 Callable callable = CodeFactory::OrdinaryToPrimitive(
89 isolate(), (hint == ToPrimitiveHint::kString)
90 ? OrdinaryToPrimitiveHint::kString
91 : OrdinaryToPrimitiveHint::kNumber);
92 TailCallStub(callable, context, input);
93 }
94 }
95
96 TF_BUILTIN(NonPrimitiveToPrimitive_Default, ConversionBuiltinsAssembler) {
97 Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kDefault);
98 }
99
100 TF_BUILTIN(NonPrimitiveToPrimitive_Number, ConversionBuiltinsAssembler) {
101 Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kNumber);
102 }
103
104 TF_BUILTIN(NonPrimitiveToPrimitive_String, ConversionBuiltinsAssembler) {
105 Generate_NonPrimitiveToPrimitive(ToPrimitiveHint::kString);
106 }
107
108 TF_BUILTIN(StringToNumber, CodeStubAssembler) {
109 Node* input = Parameter(TypeConversionDescriptor::kArgument);
110 Node* context = Parameter(TypeConversionDescriptor::kContext);
111
112 Return(StringToNumber(context, input));
113 }
114
115 TF_BUILTIN(ToName, CodeStubAssembler) {
116 Node* input = Parameter(TypeConversionDescriptor::kArgument);
117 Node* context = Parameter(TypeConversionDescriptor::kContext);
118
119 Return(ToName(context, input));
120 }
121
122 TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) {
123 Node* input = Parameter(TypeConversionDescriptor::kArgument);
124 Node* context = Parameter(TypeConversionDescriptor::kContext);
125
126 Return(NonNumberToNumber(context, input));
127 }
128
129 // ES6 section 7.1.3 ToNumber ( argument )
130 TF_BUILTIN(ToNumber, CodeStubAssembler) {
131 Node* input = Parameter(TypeConversionDescriptor::kArgument);
132 Node* context = Parameter(TypeConversionDescriptor::kContext);
133
134 Return(ToNumber(context, input));
135 }
136
137 TF_BUILTIN(ToString, CodeStubAssembler) {
138 Node* input = Parameter(TypeConversionDescriptor::kArgument);
139 Node* context = Parameter(TypeConversionDescriptor::kContext);
140
141 Label is_number(this);
142 Label runtime(this);
143
144 GotoIf(TaggedIsSmi(input), &is_number);
145
146 Node* input_map = LoadMap(input);
147 Node* input_instance_type = LoadMapInstanceType(input_map);
148
149 Label not_string(this);
150 GotoIfNot(IsStringInstanceType(input_instance_type), &not_string);
151 Return(input);
152
153 Label not_heap_number(this);
154
155 Bind(&not_string);
156 { Branch(IsHeapNumberMap(input_map), &is_number, &not_heap_number); }
157
158 Bind(&is_number);
159 { Return(NumberToString(context, input)); }
160
161 Bind(&not_heap_number);
162 {
163 GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)),
164 &runtime);
165 Return(LoadObjectField(input, Oddball::kToStringOffset));
166 }
167
168 Bind(&runtime);
169 { Return(CallRuntime(Runtime::kToString, context, input)); }
170 }
171
172 Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
173 switch (hint) {
174 case OrdinaryToPrimitiveHint::kNumber:
175 return OrdinaryToPrimitive_Number();
176 case OrdinaryToPrimitiveHint::kString:
177 return OrdinaryToPrimitive_String();
178 }
179 UNREACHABLE();
180 return Handle<Code>::null();
181 }
182
183 // 7.1.1.1 OrdinaryToPrimitive ( O, hint )
184 void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
185 OrdinaryToPrimitiveHint hint) {
186 Node* input = Parameter(TypeConversionDescriptor::kArgument);
187 Node* context = Parameter(TypeConversionDescriptor::kContext);
188
189 Variable var_result(this, MachineRepresentation::kTagged);
190 Label return_result(this, &var_result);
191
192 Handle<String> method_names[2];
193 switch (hint) {
194 case OrdinaryToPrimitiveHint::kNumber:
195 method_names[0] = factory()->valueOf_string();
196 method_names[1] = factory()->toString_string();
197 break;
198 case OrdinaryToPrimitiveHint::kString:
199 method_names[0] = factory()->toString_string();
200 method_names[1] = factory()->valueOf_string();
201 break;
202 }
203 for (Handle<String> name : method_names) {
204 // Lookup the {name} on the {input}.
205 Node* method = GetProperty(context, input, name);
206
207 // Check if the {method} is callable.
208 Label if_methodiscallable(this),
209 if_methodisnotcallable(this, Label::kDeferred);
210 GotoIf(TaggedIsSmi(method), &if_methodisnotcallable);
211 Node* method_map = LoadMap(method);
212 Branch(IsCallableMap(method_map), &if_methodiscallable,
213 &if_methodisnotcallable);
214
215 Bind(&if_methodiscallable);
216 {
217 // Call the {method} on the {input}.
218 Callable callable = CodeFactory::Call(
219 isolate(), ConvertReceiverMode::kNotNullOrUndefined);
220 Node* result = CallJS(callable, context, method, input);
221 var_result.Bind(result);
222
223 // Return the {result} if it is a primitive.
224 GotoIf(TaggedIsSmi(result), &return_result);
225 Node* result_instance_type = LoadInstanceType(result);
226 STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
227 GotoIf(Int32LessThanOrEqual(result_instance_type,
228 Int32Constant(LAST_PRIMITIVE_TYPE)),
229 &return_result);
230 }
231
232 // Just continue with the next {name} if the {method} is not callable.
233 Goto(&if_methodisnotcallable);
234 Bind(&if_methodisnotcallable);
235 }
236
237 TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
238
239 Bind(&return_result);
240 Return(var_result.value());
241 }
242
243 TF_BUILTIN(OrdinaryToPrimitive_Number, ConversionBuiltinsAssembler) {
244 Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint::kNumber);
245 }
246
247 TF_BUILTIN(OrdinaryToPrimitive_String, ConversionBuiltinsAssembler) {
248 Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint::kString);
249 }
250
251 // ES6 section 7.1.2 ToBoolean ( argument )
252 TF_BUILTIN(ToBoolean, CodeStubAssembler) {
253 Node* value = Parameter(TypeConversionDescriptor::kArgument);
254
255 Label return_true(this), return_false(this);
256 BranchIfToBooleanIsTrue(value, &return_true, &return_false);
257
258 Bind(&return_true);
259 Return(BooleanConstant(true));
260
261 Bind(&return_false);
262 Return(BooleanConstant(false));
263 }
264
265 TF_BUILTIN(ToLength, CodeStubAssembler) {
266 Node* context = Parameter(1);
267
268 // We might need to loop once for ToNumber conversion.
269 Variable var_len(this, MachineRepresentation::kTagged, Parameter(0));
270 Label loop(this, &var_len);
271 Goto(&loop);
272 Bind(&loop);
273 {
274 // Shared entry points.
275 Label return_len(this), return_two53minus1(this, Label::kDeferred),
276 return_zero(this, Label::kDeferred);
277
278 // Load the current {len} value.
279 Node* len = var_len.value();
280
281 // Check if {len} is a positive Smi.
282 GotoIf(TaggedIsPositiveSmi(len), &return_len);
283
284 // Check if {len} is a (negative) Smi.
285 GotoIf(TaggedIsSmi(len), &return_zero);
286
287 // Check if {len} is a HeapNumber.
288 Label if_lenisheapnumber(this),
289 if_lenisnotheapnumber(this, Label::kDeferred);
290 Branch(IsHeapNumberMap(LoadMap(len)), &if_lenisheapnumber,
291 &if_lenisnotheapnumber);
292
293 Bind(&if_lenisheapnumber);
294 {
295 // Load the floating-point value of {len}.
296 Node* len_value = LoadHeapNumberValue(len);
297
298 // Check if {len} is not greater than zero.
299 GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)),
300 &return_zero);
301
302 // Check if {len} is greater than or equal to 2^53-1.
303 GotoIf(Float64GreaterThanOrEqual(len_value,
304 Float64Constant(kMaxSafeInteger)),
305 &return_two53minus1);
306
307 // Round the {len} towards -Infinity.
308 Node* value = Float64Floor(len_value);
309 Node* result = ChangeFloat64ToTagged(value);
310 Return(result);
311 }
312
313 Bind(&if_lenisnotheapnumber);
314 {
315 // Need to convert {len} to a Number first.
316 Callable callable = CodeFactory::NonNumberToNumber(isolate());
317 var_len.Bind(CallStub(callable, context, len));
318 Goto(&loop);
319 }
320
321 Bind(&return_len);
322 Return(var_len.value());
323
324 Bind(&return_two53minus1);
325 Return(NumberConstant(kMaxSafeInteger));
326
327 Bind(&return_zero);
328 Return(SmiConstant(Smi::kZero));
329 }
330 }
331
332 TF_BUILTIN(ToInteger, CodeStubAssembler) {
333 Node* input = Parameter(TypeConversionDescriptor::kArgument);
334 Node* context = Parameter(TypeConversionDescriptor::kContext);
335
336 Return(ToInteger(context, input));
337 }
338
339 // ES6 section 7.1.13 ToObject (argument)
340 TF_BUILTIN(ToObject, CodeStubAssembler) {
341 Label if_number(this, Label::kDeferred), if_notsmi(this), if_jsreceiver(this),
342 if_noconstructor(this, Label::kDeferred), if_wrapjsvalue(this);
343
344 Node* object = Parameter(TypeConversionDescriptor::kArgument);
345 Node* context = Parameter(TypeConversionDescriptor::kContext);
346
347 Variable constructor_function_index_var(this,
348 MachineType::PointerRepresentation());
349
350 Branch(TaggedIsSmi(object), &if_number, &if_notsmi);
351
352 Bind(&if_notsmi);
353 Node* map = LoadMap(object);
354
355 GotoIf(IsHeapNumberMap(map), &if_number);
356
357 Node* instance_type = LoadMapInstanceType(map);
358 GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver);
359
360 Node* constructor_function_index = LoadMapConstructorFunctionIndex(map);
361 GotoIf(WordEqual(constructor_function_index,
362 IntPtrConstant(Map::kNoConstructorFunctionIndex)),
363 &if_noconstructor);
364 constructor_function_index_var.Bind(constructor_function_index);
365 Goto(&if_wrapjsvalue);
366
367 Bind(&if_number);
368 constructor_function_index_var.Bind(
369 IntPtrConstant(Context::NUMBER_FUNCTION_INDEX));
370 Goto(&if_wrapjsvalue);
371
372 Bind(&if_wrapjsvalue);
373 Node* native_context = LoadNativeContext(context);
374 Node* constructor = LoadFixedArrayElement(
375 native_context, constructor_function_index_var.value());
376 Node* initial_map =
377 LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
378 Node* js_value = Allocate(JSValue::kSize);
379 StoreMapNoWriteBarrier(js_value, initial_map);
380 StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset,
381 Heap::kEmptyFixedArrayRootIndex);
382 StoreObjectFieldRoot(js_value, JSObject::kElementsOffset,
383 Heap::kEmptyFixedArrayRootIndex);
384 StoreObjectField(js_value, JSValue::kValueOffset, object);
385 Return(js_value);
386
387 Bind(&if_noconstructor);
388 TailCallRuntime(
389 Runtime::kThrowUndefinedOrNullToObject, context,
390 HeapConstant(factory()->NewStringFromAsciiChecked("ToObject", TENURED)));
391
392 Bind(&if_jsreceiver);
393 Return(object);
394 }
395
396 // Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf).
397 TF_BUILTIN(ClassOf, CodeStubAssembler) {
398 Node* object = Parameter(TypeofDescriptor::kObject);
399
400 Return(ClassOf(object));
401 }
402
403 // ES6 section 12.5.5 typeof operator
404 TF_BUILTIN(Typeof, CodeStubAssembler) {
405 Node* object = Parameter(TypeofDescriptor::kObject);
406
407 Return(Typeof(object));
408 }
409
410 } // namespace internal
411 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-constructor-gen.cc ('k') | src/builtins/builtins-conversion-gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698