OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | |
8 #include "src/code-stub-assembler.h" | 7 #include "src/code-stub-assembler.h" |
9 #include "src/conversions.h" | |
10 #include "src/counters.h" | |
11 #include "src/objects-inl.h" | |
12 | 8 |
13 namespace v8 { | 9 namespace v8 { |
14 namespace internal { | 10 namespace internal { |
15 | 11 |
| 12 // ----------------------------------------------------------------------------- |
| 13 // ES6 section 20.1 Number Objects |
| 14 |
16 class NumberBuiltinsAssembler : public CodeStubAssembler { | 15 class NumberBuiltinsAssembler : public CodeStubAssembler { |
17 public: | 16 public: |
18 explicit NumberBuiltinsAssembler(compiler::CodeAssemblerState* state) | 17 explicit NumberBuiltinsAssembler(compiler::CodeAssemblerState* state) |
19 : CodeStubAssembler(state) {} | 18 : CodeStubAssembler(state) {} |
20 | 19 |
21 protected: | 20 protected: |
22 template <Signedness signed_result = kSigned> | 21 template <Signedness signed_result = kSigned> |
23 void BitwiseOp(std::function<Node*(Node* lhs, Node* rhs)> body) { | 22 void BitwiseOp(std::function<Node*(Node* lhs, Node* rhs)> body) { |
24 Node* left = Parameter(0); | 23 Node* left = Parameter(0); |
25 Node* right = Parameter(1); | 24 Node* right = Parameter(1); |
(...skipping 17 matching lines...) Expand all Loading... |
43 | 42 |
44 void RelationalComparisonBuiltin(RelationalComparisonMode mode) { | 43 void RelationalComparisonBuiltin(RelationalComparisonMode mode) { |
45 Node* lhs = Parameter(0); | 44 Node* lhs = Parameter(0); |
46 Node* rhs = Parameter(1); | 45 Node* rhs = Parameter(1); |
47 Node* context = Parameter(2); | 46 Node* context = Parameter(2); |
48 | 47 |
49 Return(RelationalComparison(mode, lhs, rhs, context)); | 48 Return(RelationalComparison(mode, lhs, rhs, context)); |
50 } | 49 } |
51 }; | 50 }; |
52 | 51 |
53 // ----------------------------------------------------------------------------- | |
54 // ES6 section 20.1 Number Objects | |
55 | |
56 // ES6 section 20.1.2.2 Number.isFinite ( number ) | 52 // ES6 section 20.1.2.2 Number.isFinite ( number ) |
57 TF_BUILTIN(NumberIsFinite, CodeStubAssembler) { | 53 TF_BUILTIN(NumberIsFinite, CodeStubAssembler) { |
58 Node* number = Parameter(1); | 54 Node* number = Parameter(1); |
59 | 55 |
60 Label return_true(this), return_false(this); | 56 Label return_true(this), return_false(this); |
61 | 57 |
62 // Check if {number} is a Smi. | 58 // Check if {number} is a Smi. |
63 GotoIf(TaggedIsSmi(number), &return_true); | 59 GotoIf(TaggedIsSmi(number), &return_true); |
64 | 60 |
65 // Check if {number} is a HeapNumber. | 61 // Check if {number} is a HeapNumber. |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 } | 325 } |
330 } | 326 } |
331 | 327 |
332 Bind(&if_generic); | 328 Bind(&if_generic); |
333 { | 329 { |
334 Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix); | 330 Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix); |
335 Return(result); | 331 Return(result); |
336 } | 332 } |
337 } | 333 } |
338 | 334 |
339 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) | |
340 BUILTIN(NumberPrototypeToExponential) { | |
341 HandleScope scope(isolate); | |
342 Handle<Object> value = args.at(0); | |
343 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | |
344 | |
345 // Unwrap the receiver {value}. | |
346 if (value->IsJSValue()) { | |
347 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
348 } | |
349 if (!value->IsNumber()) { | |
350 THROW_NEW_ERROR_RETURN_FAILURE( | |
351 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
352 isolate->factory()->NewStringFromAsciiChecked( | |
353 "Number.prototype.toExponential"))); | |
354 } | |
355 double const value_number = value->Number(); | |
356 | |
357 // Convert the {fraction_digits} to an integer first. | |
358 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
359 isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits)); | |
360 double const fraction_digits_number = fraction_digits->Number(); | |
361 | |
362 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
363 if (std::isinf(value_number)) { | |
364 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
365 : isolate->heap()->infinity_string(); | |
366 } | |
367 if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) { | |
368 THROW_NEW_ERROR_RETURN_FAILURE( | |
369 isolate, NewRangeError(MessageTemplate::kNumberFormatRange, | |
370 isolate->factory()->NewStringFromAsciiChecked( | |
371 "toExponential()"))); | |
372 } | |
373 int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate) | |
374 ? -1 | |
375 : static_cast<int>(fraction_digits_number); | |
376 char* const str = DoubleToExponentialCString(value_number, f); | |
377 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
378 DeleteArray(str); | |
379 return *result; | |
380 } | |
381 | |
382 // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits ) | |
383 BUILTIN(NumberPrototypeToFixed) { | |
384 HandleScope scope(isolate); | |
385 Handle<Object> value = args.at(0); | |
386 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | |
387 | |
388 // Unwrap the receiver {value}. | |
389 if (value->IsJSValue()) { | |
390 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
391 } | |
392 if (!value->IsNumber()) { | |
393 THROW_NEW_ERROR_RETURN_FAILURE( | |
394 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
395 isolate->factory()->NewStringFromAsciiChecked( | |
396 "Number.prototype.toFixed"))); | |
397 } | |
398 double const value_number = value->Number(); | |
399 | |
400 // Convert the {fraction_digits} to an integer first. | |
401 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
402 isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits)); | |
403 double const fraction_digits_number = fraction_digits->Number(); | |
404 | |
405 // Check if the {fraction_digits} are in the supported range. | |
406 if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) { | |
407 THROW_NEW_ERROR_RETURN_FAILURE( | |
408 isolate, NewRangeError(MessageTemplate::kNumberFormatRange, | |
409 isolate->factory()->NewStringFromAsciiChecked( | |
410 "toFixed() digits"))); | |
411 } | |
412 | |
413 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
414 if (std::isinf(value_number)) { | |
415 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
416 : isolate->heap()->infinity_string(); | |
417 } | |
418 char* const str = DoubleToFixedCString( | |
419 value_number, static_cast<int>(fraction_digits_number)); | |
420 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
421 DeleteArray(str); | |
422 return *result; | |
423 } | |
424 | |
425 // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] ) | |
426 BUILTIN(NumberPrototypeToLocaleString) { | |
427 HandleScope scope(isolate); | |
428 Handle<Object> value = args.at(0); | |
429 | |
430 // Unwrap the receiver {value}. | |
431 if (value->IsJSValue()) { | |
432 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
433 } | |
434 if (!value->IsNumber()) { | |
435 THROW_NEW_ERROR_RETURN_FAILURE( | |
436 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
437 isolate->factory()->NewStringFromAsciiChecked( | |
438 "Number.prototype.toLocaleString"))); | |
439 } | |
440 | |
441 // Turn the {value} into a String. | |
442 return *isolate->factory()->NumberToString(value); | |
443 } | |
444 | |
445 // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision ) | |
446 BUILTIN(NumberPrototypeToPrecision) { | |
447 HandleScope scope(isolate); | |
448 Handle<Object> value = args.at(0); | |
449 Handle<Object> precision = args.atOrUndefined(isolate, 1); | |
450 | |
451 // Unwrap the receiver {value}. | |
452 if (value->IsJSValue()) { | |
453 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
454 } | |
455 if (!value->IsNumber()) { | |
456 THROW_NEW_ERROR_RETURN_FAILURE( | |
457 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
458 isolate->factory()->NewStringFromAsciiChecked( | |
459 "Number.prototype.toPrecision"))); | |
460 } | |
461 double const value_number = value->Number(); | |
462 | |
463 // If no {precision} was specified, just return ToString of {value}. | |
464 if (precision->IsUndefined(isolate)) { | |
465 return *isolate->factory()->NumberToString(value); | |
466 } | |
467 | |
468 // Convert the {precision} to an integer first. | |
469 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision, | |
470 Object::ToInteger(isolate, precision)); | |
471 double const precision_number = precision->Number(); | |
472 | |
473 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
474 if (std::isinf(value_number)) { | |
475 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
476 : isolate->heap()->infinity_string(); | |
477 } | |
478 if (precision_number < 1.0 || precision_number > 21.0) { | |
479 THROW_NEW_ERROR_RETURN_FAILURE( | |
480 isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange)); | |
481 } | |
482 char* const str = DoubleToPrecisionCString( | |
483 value_number, static_cast<int>(precision_number)); | |
484 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
485 DeleteArray(str); | |
486 return *result; | |
487 } | |
488 | |
489 // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] ) | |
490 BUILTIN(NumberPrototypeToString) { | |
491 HandleScope scope(isolate); | |
492 Handle<Object> value = args.at(0); | |
493 Handle<Object> radix = args.atOrUndefined(isolate, 1); | |
494 | |
495 // Unwrap the receiver {value}. | |
496 if (value->IsJSValue()) { | |
497 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
498 } | |
499 if (!value->IsNumber()) { | |
500 THROW_NEW_ERROR_RETURN_FAILURE( | |
501 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
502 isolate->factory()->NewStringFromAsciiChecked( | |
503 "Number.prototype.toString"))); | |
504 } | |
505 double const value_number = value->Number(); | |
506 | |
507 // If no {radix} was specified, just return ToString of {value}. | |
508 if (radix->IsUndefined(isolate)) { | |
509 return *isolate->factory()->NumberToString(value); | |
510 } | |
511 | |
512 // Convert the {radix} to an integer first. | |
513 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix, | |
514 Object::ToInteger(isolate, radix)); | |
515 double const radix_number = radix->Number(); | |
516 | |
517 // If {radix} is 10, just return ToString of {value}. | |
518 if (radix_number == 10.0) return *isolate->factory()->NumberToString(value); | |
519 | |
520 // Make sure the {radix} is within the valid range. | |
521 if (radix_number < 2.0 || radix_number > 36.0) { | |
522 THROW_NEW_ERROR_RETURN_FAILURE( | |
523 isolate, NewRangeError(MessageTemplate::kToRadixFormatRange)); | |
524 } | |
525 | |
526 // Fast case where the result is a one character string. | |
527 if ((IsUint32Double(value_number) && value_number < radix_number) || | |
528 value_number == -0.0) { | |
529 // Character array used for conversion. | |
530 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
531 return *isolate->factory()->LookupSingleCharacterStringFromCode( | |
532 kCharTable[static_cast<uint32_t>(value_number)]); | |
533 } | |
534 | |
535 // Slow case. | |
536 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
537 if (std::isinf(value_number)) { | |
538 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
539 : isolate->heap()->infinity_string(); | |
540 } | |
541 char* const str = | |
542 DoubleToRadixCString(value_number, static_cast<int>(radix_number)); | |
543 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
544 DeleteArray(str); | |
545 return *result; | |
546 } | |
547 | |
548 // ES6 section 20.1.3.7 Number.prototype.valueOf ( ) | 335 // ES6 section 20.1.3.7 Number.prototype.valueOf ( ) |
549 TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) { | 336 TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) { |
550 Node* receiver = Parameter(0); | 337 Node* receiver = Parameter(0); |
551 Node* context = Parameter(3); | 338 Node* context = Parameter(3); |
552 | 339 |
553 Node* result = ToThisValue(context, receiver, PrimitiveType::kNumber, | 340 Node* result = ToThisValue(context, receiver, PrimitiveType::kNumber, |
554 "Number.prototype.valueOf"); | 341 "Number.prototype.valueOf"); |
555 Return(result); | 342 Return(result); |
556 } | 343 } |
557 | 344 |
(...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1592 | 1379 |
1593 TF_BUILTIN(StrictEqual, CodeStubAssembler) { | 1380 TF_BUILTIN(StrictEqual, CodeStubAssembler) { |
1594 Node* lhs = Parameter(0); | 1381 Node* lhs = Parameter(0); |
1595 Node* rhs = Parameter(1); | 1382 Node* rhs = Parameter(1); |
1596 | 1383 |
1597 Return(StrictEqual(lhs, rhs)); | 1384 Return(StrictEqual(lhs, rhs)); |
1598 } | 1385 } |
1599 | 1386 |
1600 } // namespace internal | 1387 } // namespace internal |
1601 } // namespace v8 | 1388 } // namespace v8 |
OLD | NEW |