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
9 namespace v8 {
10 namespace internal {
11
12 // -----------------------------------------------------------------------------
13 // ES6 section 20.1 Number Objects
14
15 // ES6 section 20.1.2.2 Number.isFinite ( number )
Generate_NumberIsFinite(CodeStubAssembler * assembler)16 void Builtins::Generate_NumberIsFinite(CodeStubAssembler* assembler) {
17 typedef CodeStubAssembler::Label Label;
18 typedef compiler::Node Node;
19
20 Node* number = assembler->Parameter(1);
21
22 Label return_true(assembler), return_false(assembler);
23
24 // Check if {number} is a Smi.
25 assembler->GotoIf(assembler->TaggedIsSmi(number), &return_true);
26
27 // Check if {number} is a HeapNumber.
28 assembler->GotoUnless(
29 assembler->WordEqual(assembler->LoadMap(number),
30 assembler->HeapNumberMapConstant()),
31 &return_false);
32
33 // Check if {number} contains a finite, non-NaN value.
34 Node* number_value = assembler->LoadHeapNumberValue(number);
35 assembler->BranchIfFloat64IsNaN(
36 assembler->Float64Sub(number_value, number_value), &return_false,
37 &return_true);
38
39 assembler->Bind(&return_true);
40 assembler->Return(assembler->BooleanConstant(true));
41
42 assembler->Bind(&return_false);
43 assembler->Return(assembler->BooleanConstant(false));
44 }
45
46 // ES6 section 20.1.2.3 Number.isInteger ( number )
Generate_NumberIsInteger(CodeStubAssembler * assembler)47 void Builtins::Generate_NumberIsInteger(CodeStubAssembler* assembler) {
48 typedef CodeStubAssembler::Label Label;
49 typedef compiler::Node Node;
50
51 Node* number = assembler->Parameter(1);
52
53 Label return_true(assembler), return_false(assembler);
54
55 // Check if {number} is a Smi.
56 assembler->GotoIf(assembler->TaggedIsSmi(number), &return_true);
57
58 // Check if {number} is a HeapNumber.
59 assembler->GotoUnless(
60 assembler->WordEqual(assembler->LoadMap(number),
61 assembler->HeapNumberMapConstant()),
62 &return_false);
63
64 // Load the actual value of {number}.
65 Node* number_value = assembler->LoadHeapNumberValue(number);
66
67 // Truncate the value of {number} to an integer (or an infinity).
68 Node* integer = assembler->Float64Trunc(number_value);
69
70 // Check if {number}s value matches the integer (ruling out the infinities).
71 assembler->Branch(
72 assembler->Float64Equal(assembler->Float64Sub(number_value, integer),
73 assembler->Float64Constant(0.0)),
74 &return_true, &return_false);
75
76 assembler->Bind(&return_true);
77 assembler->Return(assembler->BooleanConstant(true));
78
79 assembler->Bind(&return_false);
80 assembler->Return(assembler->BooleanConstant(false));
81 }
82
83 // ES6 section 20.1.2.4 Number.isNaN ( number )
Generate_NumberIsNaN(CodeStubAssembler * assembler)84 void Builtins::Generate_NumberIsNaN(CodeStubAssembler* assembler) {
85 typedef CodeStubAssembler::Label Label;
86 typedef compiler::Node Node;
87
88 Node* number = assembler->Parameter(1);
89
90 Label return_true(assembler), return_false(assembler);
91
92 // Check if {number} is a Smi.
93 assembler->GotoIf(assembler->TaggedIsSmi(number), &return_false);
94
95 // Check if {number} is a HeapNumber.
96 assembler->GotoUnless(
97 assembler->WordEqual(assembler->LoadMap(number),
98 assembler->HeapNumberMapConstant()),
99 &return_false);
100
101 // Check if {number} contains a NaN value.
102 Node* number_value = assembler->LoadHeapNumberValue(number);
103 assembler->BranchIfFloat64IsNaN(number_value, &return_true, &return_false);
104
105 assembler->Bind(&return_true);
106 assembler->Return(assembler->BooleanConstant(true));
107
108 assembler->Bind(&return_false);
109 assembler->Return(assembler->BooleanConstant(false));
110 }
111
112 // ES6 section 20.1.2.5 Number.isSafeInteger ( number )
Generate_NumberIsSafeInteger(CodeStubAssembler * assembler)113 void Builtins::Generate_NumberIsSafeInteger(CodeStubAssembler* assembler) {
114 typedef CodeStubAssembler::Label Label;
115 typedef compiler::Node Node;
116
117 Node* number = assembler->Parameter(1);
118
119 Label return_true(assembler), return_false(assembler);
120
121 // Check if {number} is a Smi.
122 assembler->GotoIf(assembler->TaggedIsSmi(number), &return_true);
123
124 // Check if {number} is a HeapNumber.
125 assembler->GotoUnless(
126 assembler->WordEqual(assembler->LoadMap(number),
127 assembler->HeapNumberMapConstant()),
128 &return_false);
129
130 // Load the actual value of {number}.
131 Node* number_value = assembler->LoadHeapNumberValue(number);
132
133 // Truncate the value of {number} to an integer (or an infinity).
134 Node* integer = assembler->Float64Trunc(number_value);
135
136 // Check if {number}s value matches the integer (ruling out the infinities).
137 assembler->GotoUnless(
138 assembler->Float64Equal(assembler->Float64Sub(number_value, integer),
139 assembler->Float64Constant(0.0)),
140 &return_false);
141
142 // Check if the {integer} value is in safe integer range.
143 assembler->Branch(assembler->Float64LessThanOrEqual(
144 assembler->Float64Abs(integer),
145 assembler->Float64Constant(kMaxSafeInteger)),
146 &return_true, &return_false);
147
148 assembler->Bind(&return_true);
149 assembler->Return(assembler->BooleanConstant(true));
150
151 assembler->Bind(&return_false);
152 assembler->Return(assembler->BooleanConstant(false));
153 }
154
155 // ES6 section 20.1.2.12 Number.parseFloat ( string )
Generate_NumberParseFloat(CodeStubAssembler * assembler)156 void Builtins::Generate_NumberParseFloat(CodeStubAssembler* assembler) {
157 typedef CodeStubAssembler::Label Label;
158 typedef compiler::Node Node;
159 typedef CodeStubAssembler::Variable Variable;
160
161 Node* context = assembler->Parameter(4);
162
163 // We might need to loop once for ToString conversion.
164 Variable var_input(assembler, MachineRepresentation::kTagged);
165 Label loop(assembler, &var_input);
166 var_input.Bind(assembler->Parameter(1));
167 assembler->Goto(&loop);
168 assembler->Bind(&loop);
169 {
170 // Load the current {input} value.
171 Node* input = var_input.value();
172
173 // Check if the {input} is a HeapObject or a Smi.
174 Label if_inputissmi(assembler), if_inputisnotsmi(assembler);
175 assembler->Branch(assembler->TaggedIsSmi(input), &if_inputissmi,
176 &if_inputisnotsmi);
177
178 assembler->Bind(&if_inputissmi);
179 {
180 // The {input} is already a Number, no need to do anything.
181 assembler->Return(input);
182 }
183
184 assembler->Bind(&if_inputisnotsmi);
185 {
186 // The {input} is a HeapObject, check if it's already a String.
187 Label if_inputisstring(assembler), if_inputisnotstring(assembler);
188 Node* input_map = assembler->LoadMap(input);
189 Node* input_instance_type = assembler->LoadMapInstanceType(input_map);
190 assembler->Branch(assembler->IsStringInstanceType(input_instance_type),
191 &if_inputisstring, &if_inputisnotstring);
192
193 assembler->Bind(&if_inputisstring);
194 {
195 // The {input} is already a String, check if {input} contains
196 // a cached array index.
197 Label if_inputcached(assembler), if_inputnotcached(assembler);
198 Node* input_hash = assembler->LoadNameHashField(input);
199 Node* input_bit = assembler->Word32And(
200 input_hash,
201 assembler->Int32Constant(String::kContainsCachedArrayIndexMask));
202 assembler->Branch(
203 assembler->Word32Equal(input_bit, assembler->Int32Constant(0)),
204 &if_inputcached, &if_inputnotcached);
205
206 assembler->Bind(&if_inputcached);
207 {
208 // Just return the {input}s cached array index.
209 Node* input_array_index =
210 assembler->DecodeWordFromWord32<String::ArrayIndexValueBits>(
211 input_hash);
212 assembler->Return(assembler->SmiTag(input_array_index));
213 }
214
215 assembler->Bind(&if_inputnotcached);
216 {
217 // Need to fall back to the runtime to convert {input} to double.
218 assembler->Return(assembler->CallRuntime(Runtime::kStringParseFloat,
219 context, input));
220 }
221 }
222
223 assembler->Bind(&if_inputisnotstring);
224 {
225 // The {input} is neither a String nor a Smi, check for HeapNumber.
226 Label if_inputisnumber(assembler),
227 if_inputisnotnumber(assembler, Label::kDeferred);
228 assembler->Branch(
229 assembler->WordEqual(input_map, assembler->HeapNumberMapConstant()),
230 &if_inputisnumber, &if_inputisnotnumber);
231
232 assembler->Bind(&if_inputisnumber);
233 {
234 // The {input} is already a Number, take care of -0.
235 Label if_inputiszero(assembler), if_inputisnotzero(assembler);
236 Node* input_value = assembler->LoadHeapNumberValue(input);
237 assembler->Branch(assembler->Float64Equal(
238 input_value, assembler->Float64Constant(0.0)),
239 &if_inputiszero, &if_inputisnotzero);
240
241 assembler->Bind(&if_inputiszero);
242 assembler->Return(assembler->SmiConstant(0));
243
244 assembler->Bind(&if_inputisnotzero);
245 assembler->Return(input);
246 }
247
248 assembler->Bind(&if_inputisnotnumber);
249 {
250 // Need to convert the {input} to String first.
251 // TODO(bmeurer): This could be more efficient if necessary.
252 Callable callable = CodeFactory::ToString(assembler->isolate());
253 var_input.Bind(assembler->CallStub(callable, context, input));
254 assembler->Goto(&loop);
255 }
256 }
257 }
258 }
259 }
260
261 // ES6 section 20.1.2.13 Number.parseInt ( string, radix )
Generate_NumberParseInt(CodeStubAssembler * assembler)262 void Builtins::Generate_NumberParseInt(CodeStubAssembler* assembler) {
263 typedef CodeStubAssembler::Label Label;
264 typedef compiler::Node Node;
265
266 Node* input = assembler->Parameter(1);
267 Node* radix = assembler->Parameter(2);
268 Node* context = assembler->Parameter(5);
269
270 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10).
271 Label if_radix10(assembler), if_generic(assembler, Label::kDeferred);
272 assembler->GotoIf(assembler->WordEqual(radix, assembler->UndefinedConstant()),
273 &if_radix10);
274 assembler->GotoIf(
275 assembler->WordEqual(radix, assembler->SmiConstant(Smi::FromInt(10))),
276 &if_radix10);
277 assembler->GotoIf(
278 assembler->WordEqual(radix, assembler->SmiConstant(Smi::FromInt(0))),
279 &if_radix10);
280 assembler->Goto(&if_generic);
281
282 assembler->Bind(&if_radix10);
283 {
284 // Check if we can avoid the ToString conversion on {input}.
285 Label if_inputissmi(assembler), if_inputisheapnumber(assembler),
286 if_inputisstring(assembler);
287 assembler->GotoIf(assembler->TaggedIsSmi(input), &if_inputissmi);
288 Node* input_map = assembler->LoadMap(input);
289 assembler->GotoIf(
290 assembler->WordEqual(input_map, assembler->HeapNumberMapConstant()),
291 &if_inputisheapnumber);
292 Node* input_instance_type = assembler->LoadMapInstanceType(input_map);
293 assembler->Branch(assembler->IsStringInstanceType(input_instance_type),
294 &if_inputisstring, &if_generic);
295
296 assembler->Bind(&if_inputissmi);
297 {
298 // Just return the {input}.
299 assembler->Return(input);
300 }
301
302 assembler->Bind(&if_inputisheapnumber);
303 {
304 // Check if the {input} value is in Signed32 range.
305 Label if_inputissigned32(assembler);
306 Node* input_value = assembler->LoadHeapNumberValue(input);
307 Node* input_value32 = assembler->TruncateFloat64ToWord32(input_value);
308 assembler->GotoIf(
309 assembler->Float64Equal(
310 input_value, assembler->ChangeInt32ToFloat64(input_value32)),
311 &if_inputissigned32);
312
313 // Check if the absolute {input} value is in the ]0.01,1e9[ range.
314 Node* input_value_abs = assembler->Float64Abs(input_value);
315
316 assembler->GotoUnless(
317 assembler->Float64LessThan(input_value_abs,
318 assembler->Float64Constant(1e9)),
319 &if_generic);
320 assembler->Branch(assembler->Float64LessThan(
321 assembler->Float64Constant(0.01), input_value_abs),
322 &if_inputissigned32, &if_generic);
323
324 // Return the truncated int32 value, and return the tagged result.
325 assembler->Bind(&if_inputissigned32);
326 Node* result = assembler->ChangeInt32ToTagged(input_value32);
327 assembler->Return(result);
328 }
329
330 assembler->Bind(&if_inputisstring);
331 {
332 // Check if the String {input} has a cached array index.
333 Node* input_hash = assembler->LoadNameHashField(input);
334 Node* input_bit = assembler->Word32And(
335 input_hash,
336 assembler->Int32Constant(String::kContainsCachedArrayIndexMask));
337 assembler->GotoIf(
338 assembler->Word32NotEqual(input_bit, assembler->Int32Constant(0)),
339 &if_generic);
340
341 // Return the cached array index as result.
342 Node* input_index =
343 assembler->DecodeWordFromWord32<String::ArrayIndexValueBits>(
344 input_hash);
345 Node* result = assembler->SmiTag(input_index);
346 assembler->Return(result);
347 }
348 }
349
350 assembler->Bind(&if_generic);
351 {
352 Node* result =
353 assembler->CallRuntime(Runtime::kStringParseInt, context, input, radix);
354 assembler->Return(result);
355 }
356 }
357
358 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits )
BUILTIN(NumberPrototypeToExponential)359 BUILTIN(NumberPrototypeToExponential) {
360 HandleScope scope(isolate);
361 Handle<Object> value = args.at<Object>(0);
362 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
363
364 // Unwrap the receiver {value}.
365 if (value->IsJSValue()) {
366 value = handle(Handle<JSValue>::cast(value)->value(), isolate);
367 }
368 if (!value->IsNumber()) {
369 THROW_NEW_ERROR_RETURN_FAILURE(
370 isolate, NewTypeError(MessageTemplate::kNotGeneric,
371 isolate->factory()->NewStringFromAsciiChecked(
372 "Number.prototype.toExponential")));
373 }
374 double const value_number = value->Number();
375
376 // Convert the {fraction_digits} to an integer first.
377 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
378 isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
379 double const fraction_digits_number = fraction_digits->Number();
380
381 if (std::isnan(value_number)) return isolate->heap()->nan_string();
382 if (std::isinf(value_number)) {
383 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
384 : isolate->heap()->infinity_string();
385 }
386 if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) {
387 THROW_NEW_ERROR_RETURN_FAILURE(
388 isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
389 isolate->factory()->NewStringFromAsciiChecked(
390 "toExponential()")));
391 }
392 int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate)
393 ? -1
394 : static_cast<int>(fraction_digits_number);
395 char* const str = DoubleToExponentialCString(value_number, f);
396 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
397 DeleteArray(str);
398 return *result;
399 }
400
401 // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
BUILTIN(NumberPrototypeToFixed)402 BUILTIN(NumberPrototypeToFixed) {
403 HandleScope scope(isolate);
404 Handle<Object> value = args.at<Object>(0);
405 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
406
407 // Unwrap the receiver {value}.
408 if (value->IsJSValue()) {
409 value = handle(Handle<JSValue>::cast(value)->value(), isolate);
410 }
411 if (!value->IsNumber()) {
412 THROW_NEW_ERROR_RETURN_FAILURE(
413 isolate, NewTypeError(MessageTemplate::kNotGeneric,
414 isolate->factory()->NewStringFromAsciiChecked(
415 "Number.prototype.toFixed")));
416 }
417 double const value_number = value->Number();
418
419 // Convert the {fraction_digits} to an integer first.
420 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
421 isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
422 double const fraction_digits_number = fraction_digits->Number();
423
424 // Check if the {fraction_digits} are in the supported range.
425 if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) {
426 THROW_NEW_ERROR_RETURN_FAILURE(
427 isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
428 isolate->factory()->NewStringFromAsciiChecked(
429 "toFixed() digits")));
430 }
431
432 if (std::isnan(value_number)) return isolate->heap()->nan_string();
433 if (std::isinf(value_number)) {
434 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
435 : isolate->heap()->infinity_string();
436 }
437 char* const str = DoubleToFixedCString(
438 value_number, static_cast<int>(fraction_digits_number));
439 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
440 DeleteArray(str);
441 return *result;
442 }
443
444 // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
BUILTIN(NumberPrototypeToLocaleString)445 BUILTIN(NumberPrototypeToLocaleString) {
446 HandleScope scope(isolate);
447 Handle<Object> value = args.at<Object>(0);
448
449 // Unwrap the receiver {value}.
450 if (value->IsJSValue()) {
451 value = handle(Handle<JSValue>::cast(value)->value(), isolate);
452 }
453 if (!value->IsNumber()) {
454 THROW_NEW_ERROR_RETURN_FAILURE(
455 isolate, NewTypeError(MessageTemplate::kNotGeneric,
456 isolate->factory()->NewStringFromAsciiChecked(
457 "Number.prototype.toLocaleString")));
458 }
459
460 // Turn the {value} into a String.
461 return *isolate->factory()->NumberToString(value);
462 }
463
464 // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
BUILTIN(NumberPrototypeToPrecision)465 BUILTIN(NumberPrototypeToPrecision) {
466 HandleScope scope(isolate);
467 Handle<Object> value = args.at<Object>(0);
468 Handle<Object> precision = args.atOrUndefined(isolate, 1);
469
470 // Unwrap the receiver {value}.
471 if (value->IsJSValue()) {
472 value = handle(Handle<JSValue>::cast(value)->value(), isolate);
473 }
474 if (!value->IsNumber()) {
475 THROW_NEW_ERROR_RETURN_FAILURE(
476 isolate, NewTypeError(MessageTemplate::kNotGeneric,
477 isolate->factory()->NewStringFromAsciiChecked(
478 "Number.prototype.toPrecision")));
479 }
480 double const value_number = value->Number();
481
482 // If no {precision} was specified, just return ToString of {value}.
483 if (precision->IsUndefined(isolate)) {
484 return *isolate->factory()->NumberToString(value);
485 }
486
487 // Convert the {precision} to an integer first.
488 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision,
489 Object::ToInteger(isolate, precision));
490 double const precision_number = precision->Number();
491
492 if (std::isnan(value_number)) return isolate->heap()->nan_string();
493 if (std::isinf(value_number)) {
494 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
495 : isolate->heap()->infinity_string();
496 }
497 if (precision_number < 1.0 || precision_number > 21.0) {
498 THROW_NEW_ERROR_RETURN_FAILURE(
499 isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
500 }
501 char* const str = DoubleToPrecisionCString(
502 value_number, static_cast<int>(precision_number));
503 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
504 DeleteArray(str);
505 return *result;
506 }
507
508 // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
BUILTIN(NumberPrototypeToString)509 BUILTIN(NumberPrototypeToString) {
510 HandleScope scope(isolate);
511 Handle<Object> value = args.at<Object>(0);
512 Handle<Object> radix = args.atOrUndefined(isolate, 1);
513
514 // Unwrap the receiver {value}.
515 if (value->IsJSValue()) {
516 value = handle(Handle<JSValue>::cast(value)->value(), isolate);
517 }
518 if (!value->IsNumber()) {
519 THROW_NEW_ERROR_RETURN_FAILURE(
520 isolate, NewTypeError(MessageTemplate::kNotGeneric,
521 isolate->factory()->NewStringFromAsciiChecked(
522 "Number.prototype.toString")));
523 }
524 double const value_number = value->Number();
525
526 // If no {radix} was specified, just return ToString of {value}.
527 if (radix->IsUndefined(isolate)) {
528 return *isolate->factory()->NumberToString(value);
529 }
530
531 // Convert the {radix} to an integer first.
532 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
533 Object::ToInteger(isolate, radix));
534 double const radix_number = radix->Number();
535
536 // If {radix} is 10, just return ToString of {value}.
537 if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
538
539 // Make sure the {radix} is within the valid range.
540 if (radix_number < 2.0 || radix_number > 36.0) {
541 THROW_NEW_ERROR_RETURN_FAILURE(
542 isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
543 }
544
545 // Fast case where the result is a one character string.
546 if (IsUint32Double(value_number) && value_number < radix_number) {
547 // Character array used for conversion.
548 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
549 return *isolate->factory()->LookupSingleCharacterStringFromCode(
550 kCharTable[static_cast<uint32_t>(value_number)]);
551 }
552
553 // Slow case.
554 if (std::isnan(value_number)) return isolate->heap()->nan_string();
555 if (std::isinf(value_number)) {
556 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string()
557 : isolate->heap()->infinity_string();
558 }
559 char* const str =
560 DoubleToRadixCString(value_number, static_cast<int>(radix_number));
561 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
562 DeleteArray(str);
563 return *result;
564 }
565
566 // ES6 section 20.1.3.7 Number.prototype.valueOf ( )
Generate_NumberPrototypeValueOf(CodeStubAssembler * assembler)567 void Builtins::Generate_NumberPrototypeValueOf(CodeStubAssembler* assembler) {
568 typedef compiler::Node Node;
569
570 Node* receiver = assembler->Parameter(0);
571 Node* context = assembler->Parameter(3);
572
573 Node* result = assembler->ToThisValue(
574 context, receiver, PrimitiveType::kNumber, "Number.prototype.valueOf");
575 assembler->Return(result);
576 }
577
578 // static
Generate_Add(CodeStubAssembler * assembler)579 void Builtins::Generate_Add(CodeStubAssembler* assembler) {
580 typedef CodeStubAssembler::Label Label;
581 typedef compiler::Node Node;
582 typedef CodeStubAssembler::Variable Variable;
583
584 Node* left = assembler->Parameter(0);
585 Node* right = assembler->Parameter(1);
586 Node* context = assembler->Parameter(2);
587
588 // Shared entry for floating point addition.
589 Label do_fadd(assembler);
590 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64),
591 var_fadd_rhs(assembler, MachineRepresentation::kFloat64);
592
593 // We might need to loop several times due to ToPrimitive, ToString and/or
594 // ToNumber conversions.
595 Variable var_lhs(assembler, MachineRepresentation::kTagged),
596 var_rhs(assembler, MachineRepresentation::kTagged),
597 var_result(assembler, MachineRepresentation::kTagged);
598 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
599 Label loop(assembler, 2, loop_vars), end(assembler),
600 string_add_convert_left(assembler, Label::kDeferred),
601 string_add_convert_right(assembler, Label::kDeferred);
602 var_lhs.Bind(left);
603 var_rhs.Bind(right);
604 assembler->Goto(&loop);
605 assembler->Bind(&loop);
606 {
607 // Load the current {lhs} and {rhs} values.
608 Node* lhs = var_lhs.value();
609 Node* rhs = var_rhs.value();
610
611 // Check if the {lhs} is a Smi or a HeapObject.
612 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
613 assembler->Branch(assembler->TaggedIsSmi(lhs), &if_lhsissmi,
614 &if_lhsisnotsmi);
615
616 assembler->Bind(&if_lhsissmi);
617 {
618 // Check if the {rhs} is also a Smi.
619 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
620 assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi,
621 &if_rhsisnotsmi);
622
623 assembler->Bind(&if_rhsissmi);
624 {
625 // Try fast Smi addition first.
626 Node* pair = assembler->IntPtrAddWithOverflow(
627 assembler->BitcastTaggedToWord(lhs),
628 assembler->BitcastTaggedToWord(rhs));
629 Node* overflow = assembler->Projection(1, pair);
630
631 // Check if the Smi additon overflowed.
632 Label if_overflow(assembler), if_notoverflow(assembler);
633 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
634
635 assembler->Bind(&if_overflow);
636 {
637 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
638 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
639 assembler->Goto(&do_fadd);
640 }
641
642 assembler->Bind(&if_notoverflow);
643 var_result.Bind(assembler->BitcastWordToTaggedSigned(
644 assembler->Projection(0, pair)));
645 assembler->Goto(&end);
646 }
647
648 assembler->Bind(&if_rhsisnotsmi);
649 {
650 // Load the map of {rhs}.
651 Node* rhs_map = assembler->LoadMap(rhs);
652
653 // Check if the {rhs} is a HeapNumber.
654 Label if_rhsisnumber(assembler),
655 if_rhsisnotnumber(assembler, Label::kDeferred);
656 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber,
657 &if_rhsisnotnumber);
658
659 assembler->Bind(&if_rhsisnumber);
660 {
661 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
662 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
663 assembler->Goto(&do_fadd);
664 }
665
666 assembler->Bind(&if_rhsisnotnumber);
667 {
668 // Load the instance type of {rhs}.
669 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
670
671 // Check if the {rhs} is a String.
672 Label if_rhsisstring(assembler, Label::kDeferred),
673 if_rhsisnotstring(assembler, Label::kDeferred);
674 assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type),
675 &if_rhsisstring, &if_rhsisnotstring);
676
677 assembler->Bind(&if_rhsisstring);
678 {
679 var_lhs.Bind(lhs);
680 var_rhs.Bind(rhs);
681 assembler->Goto(&string_add_convert_left);
682 }
683
684 assembler->Bind(&if_rhsisnotstring);
685 {
686 // Check if {rhs} is a JSReceiver.
687 Label if_rhsisreceiver(assembler, Label::kDeferred),
688 if_rhsisnotreceiver(assembler, Label::kDeferred);
689 assembler->Branch(
690 assembler->IsJSReceiverInstanceType(rhs_instance_type),
691 &if_rhsisreceiver, &if_rhsisnotreceiver);
692
693 assembler->Bind(&if_rhsisreceiver);
694 {
695 // Convert {rhs} to a primitive first passing no hint.
696 Callable callable =
697 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate());
698 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
699 assembler->Goto(&loop);
700 }
701
702 assembler->Bind(&if_rhsisnotreceiver);
703 {
704 // Convert {rhs} to a Number first.
705 Callable callable =
706 CodeFactory::NonNumberToNumber(assembler->isolate());
707 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
708 assembler->Goto(&loop);
709 }
710 }
711 }
712 }
713 }
714
715 assembler->Bind(&if_lhsisnotsmi);
716 {
717 // Load the map and instance type of {lhs}.
718 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
719
720 // Check if {lhs} is a String.
721 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
722 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type),
723 &if_lhsisstring, &if_lhsisnotstring);
724
725 assembler->Bind(&if_lhsisstring);
726 {
727 var_lhs.Bind(lhs);
728 var_rhs.Bind(rhs);
729 assembler->Goto(&string_add_convert_right);
730 }
731
732 assembler->Bind(&if_lhsisnotstring);
733 {
734 // Check if {rhs} is a Smi.
735 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
736 assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi,
737 &if_rhsisnotsmi);
738
739 assembler->Bind(&if_rhsissmi);
740 {
741 // Check if {lhs} is a Number.
742 Label if_lhsisnumber(assembler),
743 if_lhsisnotnumber(assembler, Label::kDeferred);
744 assembler->Branch(assembler->Word32Equal(
745 lhs_instance_type,
746 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
747 &if_lhsisnumber, &if_lhsisnotnumber);
748
749 assembler->Bind(&if_lhsisnumber);
750 {
751 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them.
752 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
753 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
754 assembler->Goto(&do_fadd);
755 }
756
757 assembler->Bind(&if_lhsisnotnumber);
758 {
759 // The {lhs} is neither a Number nor a String, and the {rhs} is a
760 // Smi.
761 Label if_lhsisreceiver(assembler, Label::kDeferred),
762 if_lhsisnotreceiver(assembler, Label::kDeferred);
763 assembler->Branch(
764 assembler->IsJSReceiverInstanceType(lhs_instance_type),
765 &if_lhsisreceiver, &if_lhsisnotreceiver);
766
767 assembler->Bind(&if_lhsisreceiver);
768 {
769 // Convert {lhs} to a primitive first passing no hint.
770 Callable callable =
771 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate());
772 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
773 assembler->Goto(&loop);
774 }
775
776 assembler->Bind(&if_lhsisnotreceiver);
777 {
778 // Convert {lhs} to a Number first.
779 Callable callable =
780 CodeFactory::NonNumberToNumber(assembler->isolate());
781 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
782 assembler->Goto(&loop);
783 }
784 }
785 }
786
787 assembler->Bind(&if_rhsisnotsmi);
788 {
789 // Load the instance type of {rhs}.
790 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
791
792 // Check if {rhs} is a String.
793 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
794 assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type),
795 &if_rhsisstring, &if_rhsisnotstring);
796
797 assembler->Bind(&if_rhsisstring);
798 {
799 var_lhs.Bind(lhs);
800 var_rhs.Bind(rhs);
801 assembler->Goto(&string_add_convert_left);
802 }
803
804 assembler->Bind(&if_rhsisnotstring);
805 {
806 // Check if {lhs} is a HeapNumber.
807 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
808 assembler->Branch(assembler->Word32Equal(
809 lhs_instance_type,
810 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
811 &if_lhsisnumber, &if_lhsisnotnumber);
812
813 assembler->Bind(&if_lhsisnumber);
814 {
815 // Check if {rhs} is also a HeapNumber.
816 Label if_rhsisnumber(assembler),
817 if_rhsisnotnumber(assembler, Label::kDeferred);
818 assembler->Branch(assembler->Word32Equal(
819 rhs_instance_type,
820 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
821 &if_rhsisnumber, &if_rhsisnotnumber);
822
823 assembler->Bind(&if_rhsisnumber);
824 {
825 // Perform a floating point addition.
826 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
827 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
828 assembler->Goto(&do_fadd);
829 }
830
831 assembler->Bind(&if_rhsisnotnumber);
832 {
833 // Check if {rhs} is a JSReceiver.
834 Label if_rhsisreceiver(assembler, Label::kDeferred),
835 if_rhsisnotreceiver(assembler, Label::kDeferred);
836 assembler->Branch(
837 assembler->IsJSReceiverInstanceType(rhs_instance_type),
838 &if_rhsisreceiver, &if_rhsisnotreceiver);
839
840 assembler->Bind(&if_rhsisreceiver);
841 {
842 // Convert {rhs} to a primitive first passing no hint.
843 Callable callable = CodeFactory::NonPrimitiveToPrimitive(
844 assembler->isolate());
845 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
846 assembler->Goto(&loop);
847 }
848
849 assembler->Bind(&if_rhsisnotreceiver);
850 {
851 // Convert {rhs} to a Number first.
852 Callable callable =
853 CodeFactory::NonNumberToNumber(assembler->isolate());
854 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
855 assembler->Goto(&loop);
856 }
857 }
858 }
859
860 assembler->Bind(&if_lhsisnotnumber);
861 {
862 // Check if {lhs} is a JSReceiver.
863 Label if_lhsisreceiver(assembler, Label::kDeferred),
864 if_lhsisnotreceiver(assembler);
865 assembler->Branch(
866 assembler->IsJSReceiverInstanceType(lhs_instance_type),
867 &if_lhsisreceiver, &if_lhsisnotreceiver);
868
869 assembler->Bind(&if_lhsisreceiver);
870 {
871 // Convert {lhs} to a primitive first passing no hint.
872 Callable callable =
873 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate());
874 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
875 assembler->Goto(&loop);
876 }
877
878 assembler->Bind(&if_lhsisnotreceiver);
879 {
880 // Check if {rhs} is a JSReceiver.
881 Label if_rhsisreceiver(assembler, Label::kDeferred),
882 if_rhsisnotreceiver(assembler, Label::kDeferred);
883 assembler->Branch(
884 assembler->IsJSReceiverInstanceType(rhs_instance_type),
885 &if_rhsisreceiver, &if_rhsisnotreceiver);
886
887 assembler->Bind(&if_rhsisreceiver);
888 {
889 // Convert {rhs} to a primitive first passing no hint.
890 Callable callable = CodeFactory::NonPrimitiveToPrimitive(
891 assembler->isolate());
892 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
893 assembler->Goto(&loop);
894 }
895
896 assembler->Bind(&if_rhsisnotreceiver);
897 {
898 // Convert {lhs} to a Number first.
899 Callable callable =
900 CodeFactory::NonNumberToNumber(assembler->isolate());
901 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
902 assembler->Goto(&loop);
903 }
904 }
905 }
906 }
907 }
908 }
909 }
910 }
911 assembler->Bind(&string_add_convert_left);
912 {
913 // Convert {lhs}, which is a Smi, to a String and concatenate the
914 // resulting string with the String {rhs}.
915 Callable callable = CodeFactory::StringAdd(
916 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
917 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
918 var_rhs.value()));
919 assembler->Goto(&end);
920 }
921
922 assembler->Bind(&string_add_convert_right);
923 {
924 // Convert {lhs}, which is a Smi, to a String and concatenate the
925 // resulting string with the String {rhs}.
926 Callable callable = CodeFactory::StringAdd(
927 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED);
928 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
929 var_rhs.value()));
930 assembler->Goto(&end);
931 }
932
933 assembler->Bind(&do_fadd);
934 {
935 Node* lhs_value = var_fadd_lhs.value();
936 Node* rhs_value = var_fadd_rhs.value();
937 Node* value = assembler->Float64Add(lhs_value, rhs_value);
938 Node* result = assembler->AllocateHeapNumberWithValue(value);
939 var_result.Bind(result);
940 assembler->Goto(&end);
941 }
942 assembler->Bind(&end);
943 assembler->Return(var_result.value());
944 }
945
Generate_Subtract(CodeStubAssembler * assembler)946 void Builtins::Generate_Subtract(CodeStubAssembler* assembler) {
947 typedef CodeStubAssembler::Label Label;
948 typedef compiler::Node Node;
949 typedef CodeStubAssembler::Variable Variable;
950
951 Node* left = assembler->Parameter(0);
952 Node* right = assembler->Parameter(1);
953 Node* context = assembler->Parameter(2);
954
955 // Shared entry for floating point subtraction.
956 Label do_fsub(assembler), end(assembler);
957 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64),
958 var_fsub_rhs(assembler, MachineRepresentation::kFloat64);
959
960 // We might need to loop several times due to ToPrimitive and/or ToNumber
961 // conversions.
962 Variable var_lhs(assembler, MachineRepresentation::kTagged),
963 var_rhs(assembler, MachineRepresentation::kTagged),
964 var_result(assembler, MachineRepresentation::kTagged);
965 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
966 Label loop(assembler, 2, loop_vars);
967 var_lhs.Bind(left);
968 var_rhs.Bind(right);
969 assembler->Goto(&loop);
970 assembler->Bind(&loop);
971 {
972 // Load the current {lhs} and {rhs} values.
973 Node* lhs = var_lhs.value();
974 Node* rhs = var_rhs.value();
975
976 // Check if the {lhs} is a Smi or a HeapObject.
977 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
978 assembler->Branch(assembler->TaggedIsSmi(lhs), &if_lhsissmi,
979 &if_lhsisnotsmi);
980
981 assembler->Bind(&if_lhsissmi);
982 {
983 // Check if the {rhs} is also a Smi.
984 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
985 assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi,
986 &if_rhsisnotsmi);
987
988 assembler->Bind(&if_rhsissmi);
989 {
990 // Try a fast Smi subtraction first.
991 Node* pair = assembler->IntPtrSubWithOverflow(
992 assembler->BitcastTaggedToWord(lhs),
993 assembler->BitcastTaggedToWord(rhs));
994 Node* overflow = assembler->Projection(1, pair);
995
996 // Check if the Smi subtraction overflowed.
997 Label if_overflow(assembler), if_notoverflow(assembler);
998 assembler->Branch(overflow, &if_overflow, &if_notoverflow);
999
1000 assembler->Bind(&if_overflow);
1001 {
1002 // The result doesn't fit into Smi range.
1003 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
1004 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
1005 assembler->Goto(&do_fsub);
1006 }
1007
1008 assembler->Bind(&if_notoverflow);
1009 var_result.Bind(assembler->BitcastWordToTaggedSigned(
1010 assembler->Projection(0, pair)));
1011 assembler->Goto(&end);
1012 }
1013
1014 assembler->Bind(&if_rhsisnotsmi);
1015 {
1016 // Load the map of the {rhs}.
1017 Node* rhs_map = assembler->LoadMap(rhs);
1018
1019 // Check if {rhs} is a HeapNumber.
1020 Label if_rhsisnumber(assembler),
1021 if_rhsisnotnumber(assembler, Label::kDeferred);
1022 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber,
1023 &if_rhsisnotnumber);
1024
1025 assembler->Bind(&if_rhsisnumber);
1026 {
1027 // Perform a floating point subtraction.
1028 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
1029 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1030 assembler->Goto(&do_fsub);
1031 }
1032
1033 assembler->Bind(&if_rhsisnotnumber);
1034 {
1035 // Convert the {rhs} to a Number first.
1036 Callable callable =
1037 CodeFactory::NonNumberToNumber(assembler->isolate());
1038 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1039 assembler->Goto(&loop);
1040 }
1041 }
1042 }
1043
1044 assembler->Bind(&if_lhsisnotsmi);
1045 {
1046 // Load the map of the {lhs}.
1047 Node* lhs_map = assembler->LoadMap(lhs);
1048
1049 // Check if the {lhs} is a HeapNumber.
1050 Label if_lhsisnumber(assembler),
1051 if_lhsisnotnumber(assembler, Label::kDeferred);
1052 Node* number_map = assembler->HeapNumberMapConstant();
1053 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1054 &if_lhsisnumber, &if_lhsisnotnumber);
1055
1056 assembler->Bind(&if_lhsisnumber);
1057 {
1058 // Check if the {rhs} is a Smi.
1059 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
1060 assembler->Branch(assembler->TaggedIsSmi(rhs), &if_rhsissmi,
1061 &if_rhsisnotsmi);
1062
1063 assembler->Bind(&if_rhsissmi);
1064 {
1065 // Perform a floating point subtraction.
1066 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1067 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
1068 assembler->Goto(&do_fsub);
1069 }
1070
1071 assembler->Bind(&if_rhsisnotsmi);
1072 {
1073 // Load the map of the {rhs}.
1074 Node* rhs_map = assembler->LoadMap(rhs);
1075
1076 // Check if the {rhs} is a HeapNumber.
1077 Label if_rhsisnumber(assembler),
1078 if_rhsisnotnumber(assembler, Label::kDeferred);
1079 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1080 &if_rhsisnumber, &if_rhsisnotnumber);
1081
1082 assembler->Bind(&if_rhsisnumber);
1083 {
1084 // Perform a floating point subtraction.
1085 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
1086 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
1087 assembler->Goto(&do_fsub);
1088 }
1089
1090 assembler->Bind(&if_rhsisnotnumber);
1091 {
1092 // Convert the {rhs} to a Number first.
1093 Callable callable =
1094 CodeFactory::NonNumberToNumber(assembler->isolate());
1095 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
1096 assembler->Goto(&loop);
1097 }
1098 }
1099 }
1100
1101 assembler->Bind(&if_lhsisnotnumber);
1102 {
1103 // Convert the {lhs} to a Number first.
1104 Callable callable =
1105 CodeFactory::NonNumberToNumber(assembler->isolate());
1106 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1107 assembler->Goto(&loop);
1108 }
1109 }
1110 }
1111
1112 assembler->Bind(&do_fsub);
1113 {
1114 Node* lhs_value = var_fsub_lhs.value();
1115 Node* rhs_value = var_fsub_rhs.value();
1116 Node* value = assembler->Float64Sub(lhs_value, rhs_value);
1117 var_result.Bind(assembler->AllocateHeapNumberWithValue(value));
1118 assembler->Goto(&end);
1119 }
1120 assembler->Bind(&end);
1121 assembler->Return(var_result.value());
1122 }
1123
Generate_Multiply(CodeStubAssembler * assembler)1124 void Builtins::Generate_Multiply(CodeStubAssembler* assembler) {
1125 typedef CodeStubAssembler::Label Label;
1126 typedef compiler::Node Node;
1127 typedef CodeStubAssembler::Variable Variable;
1128
1129 Node* left = assembler->Parameter(0);
1130 Node* right = assembler->Parameter(1);
1131 Node* context = assembler->Parameter(2);
1132
1133 // Shared entry point for floating point multiplication.
1134 Label do_fmul(assembler), return_result(assembler);
1135 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64),
1136 var_rhs_float64(assembler, MachineRepresentation::kFloat64);
1137
1138 Node* number_map = assembler->HeapNumberMapConstant();
1139
1140 // We might need to loop one or two times due to ToNumber conversions.
1141 Variable var_lhs(assembler, MachineRepresentation::kTagged),
1142 var_rhs(assembler, MachineRepresentation::kTagged),
1143 var_result(assembler, MachineRepresentation::kTagged);
1144 Variable* loop_variables[] = {&var_lhs, &var_rhs};
1145 Label loop(assembler, 2, loop_variables);
1146 var_lhs.Bind(left);
1147 var_rhs.Bind(right);
1148 assembler->Goto(&loop);
1149 assembler->Bind(&loop);
1150 {
1151 Node* lhs = var_lhs.value();
1152 Node* rhs = var_rhs.value();
1153
1154 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler);
1155 assembler->Branch(assembler->TaggedIsSmi(lhs), &lhs_is_smi,
1156 &lhs_is_not_smi);
1157
1158 assembler->Bind(&lhs_is_smi);
1159 {
1160 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
1161 assembler->Branch(assembler->TaggedIsSmi(rhs), &rhs_is_smi,
1162 &rhs_is_not_smi);
1163
1164 assembler->Bind(&rhs_is_smi);
1165 {
1166 // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi,
1167 // in case of overflow.
1168 var_result.Bind(assembler->SmiMul(lhs, rhs));
1169 assembler->Goto(&return_result);
1170 }
1171
1172 assembler->Bind(&rhs_is_not_smi);
1173 {
1174 Node* rhs_map = assembler->LoadMap(rhs);
1175
1176 // Check if {rhs} is a HeapNumber.
1177 Label rhs_is_number(assembler),
1178 rhs_is_not_number(assembler, Label::kDeferred);
1179 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1180 &rhs_is_number, &rhs_is_not_number);
1181
1182 assembler->Bind(&rhs_is_number);
1183 {
1184 // Convert {lhs} to a double and multiply it with the value of {rhs}.
1185 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
1186 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
1187 assembler->Goto(&do_fmul);
1188 }
1189
1190 assembler->Bind(&rhs_is_not_number);
1191 {
1192 // Multiplication is commutative, swap {lhs} with {rhs} and loop.
1193 var_lhs.Bind(rhs);
1194 var_rhs.Bind(lhs);
1195 assembler->Goto(&loop);
1196 }
1197 }
1198 }
1199
1200 assembler->Bind(&lhs_is_not_smi);
1201 {
1202 Node* lhs_map = assembler->LoadMap(lhs);
1203
1204 // Check if {lhs} is a HeapNumber.
1205 Label lhs_is_number(assembler),
1206 lhs_is_not_number(assembler, Label::kDeferred);
1207 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
1208 &lhs_is_number, &lhs_is_not_number);
1209
1210 assembler->Bind(&lhs_is_number);
1211 {
1212 // Check if {rhs} is a Smi.
1213 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
1214 assembler->Branch(assembler->TaggedIsSmi(rhs), &rhs_is_smi,
1215 &rhs_is_not_smi);
1216
1217 assembler->Bind(&rhs_is_smi);
1218 {
1219 // Convert {rhs} to a double and multiply it with the value of {lhs}.
1220 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
1221 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
1222 assembler->Goto(&do_fmul);
1223 }
1224
1225 assembler->Bind(&rhs_is_not_smi);
1226 {
1227 Node* rhs_map = assembler->LoadMap(rhs);
1228
1229 // Check if {rhs} is a HeapNumber.
1230 Label rhs_is_number(assembler),
1231 rhs_is_not_number(assembler, Label::kDeferred);
1232 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
1233 &rhs_is_number, &rhs_is_not_number);
1234
1235 assembler->Bind(&rhs_is_number);
1236 {
1237 // Both {lhs} and {rhs} are HeapNumbers. Load their values and
1238 // multiply them.
1239 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
1240 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
1241 assembler->Goto(&do_fmul);
1242 }
1243
1244 assembler->Bind(&rhs_is_not_number);
1245 {
1246 // Multiplication is commutative, swap {lhs} with {rhs} and loop.
1247 var_lhs.Bind(rhs);
1248 var_rhs.Bind(lhs);
1249 assembler->Goto(&loop);
1250 }
1251 }
1252 }
1253
1254 assembler->Bind(&lhs_is_not_number);
1255 {
1256 // Convert {lhs} to a Number and loop.
1257 Callable callable =
1258 CodeFactory::NonNumberToNumber(assembler->isolate());
1259 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
1260 assembler->Goto(&loop);
1261 }
1262 }
1263 }
1264
1265 assembler->Bind(&do_fmul);
1266 {
1267 Node* value =
1268 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
1269 Node* result = assembler->AllocateHeapNumberWithValue(value);
1270 var_result.Bind(result);
1271 assembler->Goto(&return_result);
1272 }
1273
1274 assembler->Bind(&return_result);
1275 assembler->Return(var_result.value());
1276 }
1277
Generate_Divide(CodeStubAssembler * assembler)1278 void Builtins::Generate_Divide(CodeStubAssembler* assembler) {
1279 typedef CodeStubAssembler::Label Label;
1280 typedef compiler::Node Node;
1281 typedef CodeStubAssembler::Variable Variable;
1282
1283 Node* left = assembler->Parameter(0);
1284 Node* right = assembler->Parameter(1);
1285 Node* context = assembler->Parameter(2);
1286
1287 // Shared entry point for floating point division.
1288 Label do_fdiv(assembler), end(assembler);
1289 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
1290 var_divisor_float64(assembler, MachineRepresentation::kFloat64);
1291
1292 Node* number_map = assembler->HeapNumberMapConstant();
1293
1294 // We might need to loop one or two times due to ToNumber conversions.
1295 Variable var_dividend(assembler, MachineRepresentation::kTagged),
1296 var_divisor(assembler, MachineRepresentation::kTagged),
1297 var_result(assembler, MachineRepresentation::kTagged);
1298 Variable* loop_variables[] = {&var_dividend, &var_divisor};
1299 Label loop(assembler, 2, loop_variables);
1300 var_dividend.Bind(left);
1301 var_divisor.Bind(right);
1302 assembler->Goto(&loop);
1303 assembler->Bind(&loop);
1304 {
1305 Node* dividend = var_dividend.value();
1306 Node* divisor = var_divisor.value();
1307
1308 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
1309 assembler->Branch(assembler->TaggedIsSmi(dividend), ÷nd_is_smi,
1310 ÷nd_is_not_smi);
1311
1312 assembler->Bind(÷nd_is_smi);
1313 {
1314 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1315 assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi,
1316 &divisor_is_not_smi);
1317
1318 assembler->Bind(&divisor_is_smi);
1319 {
1320 Label bailout(assembler);
1321
1322 // Do floating point division if {divisor} is zero.
1323 assembler->GotoIf(
1324 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)),
1325 &bailout);
1326
1327 // Do floating point division {dividend} is zero and {divisor} is
1328 // negative.
1329 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler);
1330 assembler->Branch(
1331 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)),
1332 ÷nd_is_zero, ÷nd_is_not_zero);
1333
1334 assembler->Bind(÷nd_is_zero);
1335 {
1336 assembler->GotoIf(
1337 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)),
1338 &bailout);
1339 assembler->Goto(÷nd_is_not_zero);
1340 }
1341 assembler->Bind(÷nd_is_not_zero);
1342
1343 Node* untagged_divisor = assembler->SmiUntag(divisor);
1344 Node* untagged_dividend = assembler->SmiUntag(dividend);
1345
1346 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1
1347 // if the Smi size is 31) and {divisor} is -1.
1348 Label divisor_is_minus_one(assembler),
1349 divisor_is_not_minus_one(assembler);
1350 assembler->Branch(assembler->Word32Equal(untagged_divisor,
1351 assembler->Int32Constant(-1)),
1352 &divisor_is_minus_one, &divisor_is_not_minus_one);
1353
1354 assembler->Bind(&divisor_is_minus_one);
1355 {
1356 assembler->GotoIf(
1357 assembler->Word32Equal(
1358 untagged_dividend,
1359 assembler->Int32Constant(
1360 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))),
1361 &bailout);
1362 assembler->Goto(&divisor_is_not_minus_one);
1363 }
1364 assembler->Bind(&divisor_is_not_minus_one);
1365
1366 // TODO(epertoso): consider adding a machine instruction that returns
1367 // both the result and the remainder.
1368 Node* untagged_result =
1369 assembler->Int32Div(untagged_dividend, untagged_divisor);
1370 Node* truncated =
1371 assembler->Int32Mul(untagged_result, untagged_divisor);
1372 // Do floating point division if the remainder is not 0.
1373 assembler->GotoIf(
1374 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout);
1375 var_result.Bind(assembler->SmiTag(untagged_result));
1376 assembler->Goto(&end);
1377
1378 // Bailout: convert {dividend} and {divisor} to double and do double
1379 // division.
1380 assembler->Bind(&bailout);
1381 {
1382 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1383 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1384 assembler->Goto(&do_fdiv);
1385 }
1386 }
1387
1388 assembler->Bind(&divisor_is_not_smi);
1389 {
1390 Node* divisor_map = assembler->LoadMap(divisor);
1391
1392 // Check if {divisor} is a HeapNumber.
1393 Label divisor_is_number(assembler),
1394 divisor_is_not_number(assembler, Label::kDeferred);
1395 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1396 &divisor_is_number, &divisor_is_not_number);
1397
1398 assembler->Bind(&divisor_is_number);
1399 {
1400 // Convert {dividend} to a double and divide it with the value of
1401 // {divisor}.
1402 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1403 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1404 assembler->Goto(&do_fdiv);
1405 }
1406
1407 assembler->Bind(&divisor_is_not_number);
1408 {
1409 // Convert {divisor} to a number and loop.
1410 Callable callable =
1411 CodeFactory::NonNumberToNumber(assembler->isolate());
1412 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1413 assembler->Goto(&loop);
1414 }
1415 }
1416 }
1417
1418 assembler->Bind(÷nd_is_not_smi);
1419 {
1420 Node* dividend_map = assembler->LoadMap(dividend);
1421
1422 // Check if {dividend} is a HeapNumber.
1423 Label dividend_is_number(assembler),
1424 dividend_is_not_number(assembler, Label::kDeferred);
1425 assembler->Branch(assembler->WordEqual(dividend_map, number_map),
1426 ÷nd_is_number, ÷nd_is_not_number);
1427
1428 assembler->Bind(÷nd_is_number);
1429 {
1430 // Check if {divisor} is a Smi.
1431 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1432 assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi,
1433 &divisor_is_not_smi);
1434
1435 assembler->Bind(&divisor_is_smi);
1436 {
1437 // Convert {divisor} to a double and use it for a floating point
1438 // division.
1439 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1440 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1441 assembler->Goto(&do_fdiv);
1442 }
1443
1444 assembler->Bind(&divisor_is_not_smi);
1445 {
1446 Node* divisor_map = assembler->LoadMap(divisor);
1447
1448 // Check if {divisor} is a HeapNumber.
1449 Label divisor_is_number(assembler),
1450 divisor_is_not_number(assembler, Label::kDeferred);
1451 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1452 &divisor_is_number, &divisor_is_not_number);
1453
1454 assembler->Bind(&divisor_is_number);
1455 {
1456 // Both {dividend} and {divisor} are HeapNumbers. Load their values
1457 // and divide them.
1458 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1459 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1460 assembler->Goto(&do_fdiv);
1461 }
1462
1463 assembler->Bind(&divisor_is_not_number);
1464 {
1465 // Convert {divisor} to a number and loop.
1466 Callable callable =
1467 CodeFactory::NonNumberToNumber(assembler->isolate());
1468 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1469 assembler->Goto(&loop);
1470 }
1471 }
1472 }
1473
1474 assembler->Bind(÷nd_is_not_number);
1475 {
1476 // Convert {dividend} to a Number and loop.
1477 Callable callable =
1478 CodeFactory::NonNumberToNumber(assembler->isolate());
1479 var_dividend.Bind(assembler->CallStub(callable, context, dividend));
1480 assembler->Goto(&loop);
1481 }
1482 }
1483 }
1484
1485 assembler->Bind(&do_fdiv);
1486 {
1487 Node* value = assembler->Float64Div(var_dividend_float64.value(),
1488 var_divisor_float64.value());
1489 var_result.Bind(assembler->AllocateHeapNumberWithValue(value));
1490 assembler->Goto(&end);
1491 }
1492 assembler->Bind(&end);
1493 assembler->Return(var_result.value());
1494 }
1495
Generate_Modulus(CodeStubAssembler * assembler)1496 void Builtins::Generate_Modulus(CodeStubAssembler* assembler) {
1497 typedef CodeStubAssembler::Label Label;
1498 typedef compiler::Node Node;
1499 typedef CodeStubAssembler::Variable Variable;
1500
1501 Node* left = assembler->Parameter(0);
1502 Node* right = assembler->Parameter(1);
1503 Node* context = assembler->Parameter(2);
1504
1505 Variable var_result(assembler, MachineRepresentation::kTagged);
1506 Label return_result(assembler, &var_result);
1507
1508 // Shared entry point for floating point modulus.
1509 Label do_fmod(assembler);
1510 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
1511 var_divisor_float64(assembler, MachineRepresentation::kFloat64);
1512
1513 Node* number_map = assembler->HeapNumberMapConstant();
1514
1515 // We might need to loop one or two times due to ToNumber conversions.
1516 Variable var_dividend(assembler, MachineRepresentation::kTagged),
1517 var_divisor(assembler, MachineRepresentation::kTagged);
1518 Variable* loop_variables[] = {&var_dividend, &var_divisor};
1519 Label loop(assembler, 2, loop_variables);
1520 var_dividend.Bind(left);
1521 var_divisor.Bind(right);
1522 assembler->Goto(&loop);
1523 assembler->Bind(&loop);
1524 {
1525 Node* dividend = var_dividend.value();
1526 Node* divisor = var_divisor.value();
1527
1528 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
1529 assembler->Branch(assembler->TaggedIsSmi(dividend), ÷nd_is_smi,
1530 ÷nd_is_not_smi);
1531
1532 assembler->Bind(÷nd_is_smi);
1533 {
1534 Label dividend_is_not_zero(assembler);
1535 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1536 assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi,
1537 &divisor_is_not_smi);
1538
1539 assembler->Bind(&divisor_is_smi);
1540 {
1541 // Compute the modulus of two Smis.
1542 var_result.Bind(assembler->SmiMod(dividend, divisor));
1543 assembler->Goto(&return_result);
1544 }
1545
1546 assembler->Bind(&divisor_is_not_smi);
1547 {
1548 Node* divisor_map = assembler->LoadMap(divisor);
1549
1550 // Check if {divisor} is a HeapNumber.
1551 Label divisor_is_number(assembler),
1552 divisor_is_not_number(assembler, Label::kDeferred);
1553 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1554 &divisor_is_number, &divisor_is_not_number);
1555
1556 assembler->Bind(&divisor_is_number);
1557 {
1558 // Convert {dividend} to a double and compute its modulus with the
1559 // value of {dividend}.
1560 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
1561 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1562 assembler->Goto(&do_fmod);
1563 }
1564
1565 assembler->Bind(&divisor_is_not_number);
1566 {
1567 // Convert {divisor} to a number and loop.
1568 Callable callable =
1569 CodeFactory::NonNumberToNumber(assembler->isolate());
1570 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1571 assembler->Goto(&loop);
1572 }
1573 }
1574 }
1575
1576 assembler->Bind(÷nd_is_not_smi);
1577 {
1578 Node* dividend_map = assembler->LoadMap(dividend);
1579
1580 // Check if {dividend} is a HeapNumber.
1581 Label dividend_is_number(assembler),
1582 dividend_is_not_number(assembler, Label::kDeferred);
1583 assembler->Branch(assembler->WordEqual(dividend_map, number_map),
1584 ÷nd_is_number, ÷nd_is_not_number);
1585
1586 assembler->Bind(÷nd_is_number);
1587 {
1588 // Check if {divisor} is a Smi.
1589 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
1590 assembler->Branch(assembler->TaggedIsSmi(divisor), &divisor_is_smi,
1591 &divisor_is_not_smi);
1592
1593 assembler->Bind(&divisor_is_smi);
1594 {
1595 // Convert {divisor} to a double and compute {dividend}'s modulus with
1596 // it.
1597 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1598 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
1599 assembler->Goto(&do_fmod);
1600 }
1601
1602 assembler->Bind(&divisor_is_not_smi);
1603 {
1604 Node* divisor_map = assembler->LoadMap(divisor);
1605
1606 // Check if {divisor} is a HeapNumber.
1607 Label divisor_is_number(assembler),
1608 divisor_is_not_number(assembler, Label::kDeferred);
1609 assembler->Branch(assembler->WordEqual(divisor_map, number_map),
1610 &divisor_is_number, &divisor_is_not_number);
1611
1612 assembler->Bind(&divisor_is_number);
1613 {
1614 // Both {dividend} and {divisor} are HeapNumbers. Load their values
1615 // and compute their modulus.
1616 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
1617 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
1618 assembler->Goto(&do_fmod);
1619 }
1620
1621 assembler->Bind(&divisor_is_not_number);
1622 {
1623 // Convert {divisor} to a number and loop.
1624 Callable callable =
1625 CodeFactory::NonNumberToNumber(assembler->isolate());
1626 var_divisor.Bind(assembler->CallStub(callable, context, divisor));
1627 assembler->Goto(&loop);
1628 }
1629 }
1630 }
1631
1632 assembler->Bind(÷nd_is_not_number);
1633 {
1634 // Convert {dividend} to a Number and loop.
1635 Callable callable =
1636 CodeFactory::NonNumberToNumber(assembler->isolate());
1637 var_dividend.Bind(assembler->CallStub(callable, context, dividend));
1638 assembler->Goto(&loop);
1639 }
1640 }
1641 }
1642
1643 assembler->Bind(&do_fmod);
1644 {
1645 Node* value = assembler->Float64Mod(var_dividend_float64.value(),
1646 var_divisor_float64.value());
1647 var_result.Bind(assembler->AllocateHeapNumberWithValue(value));
1648 assembler->Goto(&return_result);
1649 }
1650
1651 assembler->Bind(&return_result);
1652 assembler->Return(var_result.value());
1653 }
1654
Generate_ShiftLeft(CodeStubAssembler * assembler)1655 void Builtins::Generate_ShiftLeft(CodeStubAssembler* assembler) {
1656 compiler::Node* left = assembler->Parameter(0);
1657 compiler::Node* right = assembler->Parameter(1);
1658 compiler::Node* context = assembler->Parameter(2);
1659
1660 using compiler::Node;
1661
1662 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1663 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1664 Node* shift_count =
1665 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1666 Node* value = assembler->Word32Shl(lhs_value, shift_count);
1667 Node* result = assembler->ChangeInt32ToTagged(value);
1668 assembler->Return(result);
1669 }
1670
Generate_ShiftRight(CodeStubAssembler * assembler)1671 void Builtins::Generate_ShiftRight(CodeStubAssembler* assembler) {
1672 compiler::Node* left = assembler->Parameter(0);
1673 compiler::Node* right = assembler->Parameter(1);
1674 compiler::Node* context = assembler->Parameter(2);
1675
1676 using compiler::Node;
1677
1678 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1679 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1680 Node* shift_count =
1681 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1682 Node* value = assembler->Word32Sar(lhs_value, shift_count);
1683 Node* result = assembler->ChangeInt32ToTagged(value);
1684 assembler->Return(result);
1685 }
1686
Generate_ShiftRightLogical(CodeStubAssembler * assembler)1687 void Builtins::Generate_ShiftRightLogical(CodeStubAssembler* assembler) {
1688 compiler::Node* left = assembler->Parameter(0);
1689 compiler::Node* right = assembler->Parameter(1);
1690 compiler::Node* context = assembler->Parameter(2);
1691
1692 using compiler::Node;
1693
1694 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1695 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1696 Node* shift_count =
1697 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
1698 Node* value = assembler->Word32Shr(lhs_value, shift_count);
1699 Node* result = assembler->ChangeUint32ToTagged(value);
1700 assembler->Return(result);
1701 }
1702
Generate_BitwiseAnd(CodeStubAssembler * assembler)1703 void Builtins::Generate_BitwiseAnd(CodeStubAssembler* assembler) {
1704 compiler::Node* left = assembler->Parameter(0);
1705 compiler::Node* right = assembler->Parameter(1);
1706 compiler::Node* context = assembler->Parameter(2);
1707
1708 using compiler::Node;
1709
1710 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1711 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1712 Node* value = assembler->Word32And(lhs_value, rhs_value);
1713 Node* result = assembler->ChangeInt32ToTagged(value);
1714 assembler->Return(result);
1715 }
1716
Generate_BitwiseOr(CodeStubAssembler * assembler)1717 void Builtins::Generate_BitwiseOr(CodeStubAssembler* assembler) {
1718 compiler::Node* left = assembler->Parameter(0);
1719 compiler::Node* right = assembler->Parameter(1);
1720 compiler::Node* context = assembler->Parameter(2);
1721
1722 using compiler::Node;
1723
1724 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1725 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1726 Node* value = assembler->Word32Or(lhs_value, rhs_value);
1727 Node* result = assembler->ChangeInt32ToTagged(value);
1728 assembler->Return(result);
1729 }
1730
Generate_BitwiseXor(CodeStubAssembler * assembler)1731 void Builtins::Generate_BitwiseXor(CodeStubAssembler* assembler) {
1732 compiler::Node* left = assembler->Parameter(0);
1733 compiler::Node* right = assembler->Parameter(1);
1734 compiler::Node* context = assembler->Parameter(2);
1735
1736 using compiler::Node;
1737
1738 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
1739 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
1740 Node* value = assembler->Word32Xor(lhs_value, rhs_value);
1741 Node* result = assembler->ChangeInt32ToTagged(value);
1742 assembler->Return(result);
1743 }
1744
Generate_LessThan(CodeStubAssembler * assembler)1745 void Builtins::Generate_LessThan(CodeStubAssembler* assembler) {
1746 compiler::Node* lhs = assembler->Parameter(0);
1747 compiler::Node* rhs = assembler->Parameter(1);
1748 compiler::Node* context = assembler->Parameter(2);
1749
1750 assembler->Return(assembler->RelationalComparison(
1751 CodeStubAssembler::kLessThan, lhs, rhs, context));
1752 }
1753
Generate_LessThanOrEqual(CodeStubAssembler * assembler)1754 void Builtins::Generate_LessThanOrEqual(CodeStubAssembler* assembler) {
1755 compiler::Node* lhs = assembler->Parameter(0);
1756 compiler::Node* rhs = assembler->Parameter(1);
1757 compiler::Node* context = assembler->Parameter(2);
1758
1759 assembler->Return(assembler->RelationalComparison(
1760 CodeStubAssembler::kLessThanOrEqual, lhs, rhs, context));
1761 }
1762
Generate_GreaterThan(CodeStubAssembler * assembler)1763 void Builtins::Generate_GreaterThan(CodeStubAssembler* assembler) {
1764 compiler::Node* lhs = assembler->Parameter(0);
1765 compiler::Node* rhs = assembler->Parameter(1);
1766 compiler::Node* context = assembler->Parameter(2);
1767
1768 assembler->Return(assembler->RelationalComparison(
1769 CodeStubAssembler::kGreaterThan, lhs, rhs, context));
1770 }
1771
Generate_GreaterThanOrEqual(CodeStubAssembler * assembler)1772 void Builtins::Generate_GreaterThanOrEqual(CodeStubAssembler* assembler) {
1773 compiler::Node* lhs = assembler->Parameter(0);
1774 compiler::Node* rhs = assembler->Parameter(1);
1775 compiler::Node* context = assembler->Parameter(2);
1776
1777 assembler->Return(assembler->RelationalComparison(
1778 CodeStubAssembler::kGreaterThanOrEqual, lhs, rhs, context));
1779 }
1780
Generate_Equal(CodeStubAssembler * assembler)1781 void Builtins::Generate_Equal(CodeStubAssembler* assembler) {
1782 compiler::Node* lhs = assembler->Parameter(0);
1783 compiler::Node* rhs = assembler->Parameter(1);
1784 compiler::Node* context = assembler->Parameter(2);
1785
1786 assembler->Return(assembler->Equal(CodeStubAssembler::kDontNegateResult, lhs,
1787 rhs, context));
1788 }
1789
Generate_NotEqual(CodeStubAssembler * assembler)1790 void Builtins::Generate_NotEqual(CodeStubAssembler* assembler) {
1791 compiler::Node* lhs = assembler->Parameter(0);
1792 compiler::Node* rhs = assembler->Parameter(1);
1793 compiler::Node* context = assembler->Parameter(2);
1794
1795 assembler->Return(
1796 assembler->Equal(CodeStubAssembler::kNegateResult, lhs, rhs, context));
1797 }
1798
Generate_StrictEqual(CodeStubAssembler * assembler)1799 void Builtins::Generate_StrictEqual(CodeStubAssembler* assembler) {
1800 compiler::Node* lhs = assembler->Parameter(0);
1801 compiler::Node* rhs = assembler->Parameter(1);
1802 compiler::Node* context = assembler->Parameter(2);
1803
1804 assembler->Return(assembler->StrictEqual(CodeStubAssembler::kDontNegateResult,
1805 lhs, rhs, context));
1806 }
1807
Generate_StrictNotEqual(CodeStubAssembler * assembler)1808 void Builtins::Generate_StrictNotEqual(CodeStubAssembler* assembler) {
1809 compiler::Node* lhs = assembler->Parameter(0);
1810 compiler::Node* rhs = assembler->Parameter(1);
1811 compiler::Node* context = assembler->Parameter(2);
1812
1813 assembler->Return(assembler->StrictEqual(CodeStubAssembler::kNegateResult,
1814 lhs, rhs, context));
1815 }
1816
1817 } // namespace internal
1818 } // namespace v8
1819