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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ] ] ) 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 ) 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 ] ) 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 ( ) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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