OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins.h" | 5 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/regexp/regexp-utils.h" | 9 #include "src/regexp/regexp-utils.h" |
10 | 10 |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 | 417 |
418 // ----------------------------------------------------------------------------- | 418 // ----------------------------------------------------------------------------- |
419 // ES6 section 21.1 String Objects | 419 // ES6 section 21.1 String Objects |
420 | 420 |
421 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) | 421 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) |
422 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { | 422 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { |
423 typedef CodeStubAssembler::Label Label; | 423 typedef CodeStubAssembler::Label Label; |
424 typedef compiler::Node Node; | 424 typedef compiler::Node Node; |
425 typedef CodeStubAssembler::Variable Variable; | 425 typedef CodeStubAssembler::Variable Variable; |
426 | 426 |
427 Node* code = assembler->Parameter(1); | 427 Node* argc = assembler->ChangeInt32ToIntPtr( |
428 Node* context = assembler->Parameter(4); | 428 assembler->Parameter(BuiltinDescriptor::kArgumentsCount)); |
| 429 Node* context = assembler->Parameter(BuiltinDescriptor::kContext); |
| 430 |
| 431 CodeStubArguments arguments(assembler, argc); |
429 | 432 |
430 // Check if we have exactly one argument (plus the implicit receiver), i.e. | 433 // Check if we have exactly one argument (plus the implicit receiver), i.e. |
431 // if the parent frame is not an arguments adaptor frame. | 434 // if the parent frame is not an arguments adaptor frame. |
432 Label if_oneargument(assembler), if_notoneargument(assembler); | 435 Label if_oneargument(assembler), if_notoneargument(assembler); |
433 Node* parent_frame_pointer = assembler->LoadParentFramePointer(); | 436 assembler->Branch(assembler->WordEqual(argc, assembler->IntPtrConstant(1)), |
434 Node* parent_frame_type = | 437 &if_oneargument, &if_notoneargument); |
435 assembler->Load(MachineType::Pointer(), parent_frame_pointer, | |
436 assembler->IntPtrConstant( | |
437 CommonFrameConstants::kContextOrFrameTypeOffset)); | |
438 assembler->Branch( | |
439 assembler->WordEqual( | |
440 parent_frame_type, | |
441 assembler->SmiConstant(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))), | |
442 &if_notoneargument, &if_oneargument); | |
443 | 438 |
444 assembler->Bind(&if_oneargument); | 439 assembler->Bind(&if_oneargument); |
445 { | 440 { |
446 // Single argument case, perform fast single character string cache lookup | 441 // Single argument case, perform fast single character string cache lookup |
447 // for one-byte code units, or fall back to creating a single character | 442 // for one-byte code units, or fall back to creating a single character |
448 // string on the fly otherwise. | 443 // string on the fly otherwise. |
| 444 Node* code = arguments.AtIndex(0); |
449 Node* code32 = assembler->TruncateTaggedToWord32(context, code); | 445 Node* code32 = assembler->TruncateTaggedToWord32(context, code); |
450 Node* code16 = assembler->Word32And( | 446 Node* code16 = assembler->Word32And( |
451 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); | 447 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); |
452 Node* result = assembler->StringFromCharCode(code16); | 448 Node* result = assembler->StringFromCharCode(code16); |
453 assembler->Return(result); | 449 arguments.PopAndReturn(result); |
454 } | 450 } |
455 | 451 |
| 452 Node* code16 = nullptr; |
456 assembler->Bind(&if_notoneargument); | 453 assembler->Bind(&if_notoneargument); |
457 { | 454 { |
458 // Determine the resulting string length. | 455 Label two_byte(assembler); |
459 Node* length = assembler->LoadAndUntagSmi( | 456 // Assume that the resulting string contains only one-byte characters. |
460 parent_frame_pointer, ArgumentsAdaptorFrameConstants::kLengthOffset); | 457 Node* one_byte_result = assembler->AllocateSeqOneByteString(context, argc); |
461 | 458 |
462 // Assume that the resulting string contains only one-byte characters. | 459 Variable max_index(assembler, MachineType::PointerRepresentation()); |
463 Node* result = assembler->AllocateSeqOneByteString(context, length); | 460 max_index.Bind(assembler->IntPtrConstant(0)); |
464 | 461 |
465 // Truncate all input parameters and append them to the resulting string. | 462 // Iterate over the incoming arguments, converting them to 8-bit character |
466 Variable var_offset(assembler, MachineType::PointerRepresentation()); | 463 // codes. Stop if any of the conversions generates a code that doesn't fit |
467 Label loop(assembler, &var_offset), done_loop(assembler); | 464 // in 8 bits. |
468 var_offset.Bind(assembler->IntPtrConstant(0)); | 465 CodeStubAssembler::VariableList vars({&max_index}, assembler->zone()); |
469 assembler->Goto(&loop); | 466 arguments.ForEach(vars, [context, &two_byte, &max_index, &code16, |
470 assembler->Bind(&loop); | 467 one_byte_result](CodeStubAssembler* assembler, |
471 { | 468 Node* arg) { |
472 // Load the current {offset}. | 469 Node* code32 = assembler->TruncateTaggedToWord32(context, arg); |
473 Node* offset = var_offset.value(); | 470 code16 = assembler->Word32And( |
474 | |
475 // Check if we're done with the string. | |
476 assembler->GotoIf(assembler->WordEqual(offset, length), &done_loop); | |
477 | |
478 // Load the next code point and truncate it to a 16-bit value. | |
479 Node* code = assembler->Load( | |
480 MachineType::AnyTagged(), parent_frame_pointer, | |
481 assembler->IntPtrAdd( | |
482 assembler->WordShl(assembler->IntPtrSub(length, offset), | |
483 assembler->IntPtrConstant(kPointerSizeLog2)), | |
484 assembler->IntPtrConstant( | |
485 CommonFrameConstants::kFixedFrameSizeAboveFp - | |
486 kPointerSize))); | |
487 Node* code32 = assembler->TruncateTaggedToWord32(context, code); | |
488 Node* code16 = assembler->Word32And( | |
489 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); | 471 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); |
490 | 472 |
491 // Check if {code16} fits into a one-byte string. | 473 assembler->GotoIf( |
492 Label if_codeisonebyte(assembler), if_codeistwobyte(assembler); | 474 assembler->Int32GreaterThan( |
493 assembler->Branch( | |
494 assembler->Int32LessThanOrEqual( | |
495 code16, assembler->Int32Constant(String::kMaxOneByteCharCode)), | 475 code16, assembler->Int32Constant(String::kMaxOneByteCharCode)), |
496 &if_codeisonebyte, &if_codeistwobyte); | 476 &two_byte); |
497 | 477 |
498 assembler->Bind(&if_codeisonebyte); | 478 // The {code16} fits into the SeqOneByteString {one_byte_result}. |
499 { | 479 Node* offset = assembler->ElementOffsetFromIndex( |
500 // The {code16} fits into the SeqOneByteString {result}. | 480 max_index.value(), UINT8_ELEMENTS, |
501 assembler->StoreNoWriteBarrier( | 481 CodeStubAssembler::INTPTR_PARAMETERS, |
502 MachineRepresentation::kWord8, result, | 482 SeqOneByteString::kHeaderSize - kHeapObjectTag); |
503 assembler->IntPtrAdd( | 483 assembler->StoreNoWriteBarrier(MachineRepresentation::kWord8, |
504 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | 484 one_byte_result, offset, code16); |
505 kHeapObjectTag), | 485 max_index.Bind(assembler->IntPtrAdd(max_index.value(), |
506 offset), | 486 assembler->IntPtrConstant(1))); |
507 code16); | 487 }); |
508 var_offset.Bind( | 488 arguments.PopAndReturn(one_byte_result); |
509 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | |
510 assembler->Goto(&loop); | |
511 } | |
512 | 489 |
513 assembler->Bind(&if_codeistwobyte); | 490 assembler->Bind(&two_byte); |
514 { | |
515 // Allocate a SeqTwoByteString to hold the resulting string. | |
516 Node* cresult = assembler->AllocateSeqTwoByteString(context, length); | |
517 | 491 |
518 // Copy all characters that were previously written to the | 492 // At least one of the characters in the string requires a 16-bit |
519 // SeqOneByteString in {result} over to the new {cresult}. | 493 // representation. Allocate a SeqTwoByteString to hold the resulting |
520 Variable var_coffset(assembler, MachineType::PointerRepresentation()); | 494 // string. |
521 Label cloop(assembler, &var_coffset), done_cloop(assembler); | 495 Node* two_byte_result = assembler->AllocateSeqTwoByteString(context, argc); |
522 var_coffset.Bind(assembler->IntPtrConstant(0)); | |
523 assembler->Goto(&cloop); | |
524 assembler->Bind(&cloop); | |
525 { | |
526 Node* coffset = var_coffset.value(); | |
527 assembler->GotoIf(assembler->WordEqual(coffset, offset), &done_cloop); | |
528 Node* ccode = assembler->Load( | |
529 MachineType::Uint8(), result, | |
530 assembler->IntPtrAdd( | |
531 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
532 kHeapObjectTag), | |
533 coffset)); | |
534 assembler->StoreNoWriteBarrier( | |
535 MachineRepresentation::kWord16, cresult, | |
536 assembler->IntPtrAdd( | |
537 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
538 kHeapObjectTag), | |
539 assembler->WordShl(coffset, 1)), | |
540 ccode); | |
541 var_coffset.Bind( | |
542 assembler->IntPtrAdd(coffset, assembler->IntPtrConstant(1))); | |
543 assembler->Goto(&cloop); | |
544 } | |
545 | 496 |
546 // Write the pending {code16} to {offset}. | 497 // Copy the characters that have already been put in the 8-bit string into |
547 assembler->Bind(&done_cloop); | 498 // their corresponding positions in the new 16-bit string. |
548 assembler->StoreNoWriteBarrier( | 499 Node* zero = assembler->IntPtrConstant(0); |
549 MachineRepresentation::kWord16, cresult, | 500 assembler->CopyStringCharacters( |
550 assembler->IntPtrAdd( | 501 one_byte_result, two_byte_result, zero, zero, max_index.value(), |
551 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | 502 String::ONE_BYTE_ENCODING, String::TWO_BYTE_ENCODING, |
552 kHeapObjectTag), | 503 CodeStubAssembler::INTPTR_PARAMETERS); |
553 assembler->WordShl(offset, 1)), | |
554 code16); | |
555 | 504 |
556 // Copy the remaining parameters to the SeqTwoByteString {cresult}. | 505 // Write the character that caused the 8-bit to 16-bit fault. |
557 Label floop(assembler, &var_offset), done_floop(assembler); | 506 Node* max_index_offset = assembler->ElementOffsetFromIndex( |
558 assembler->Goto(&floop); | 507 max_index.value(), UINT16_ELEMENTS, |
559 assembler->Bind(&floop); | 508 CodeStubAssembler::INTPTR_PARAMETERS, |
560 { | 509 SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
561 // Compute the next {offset}. | 510 assembler->StoreNoWriteBarrier(MachineRepresentation::kWord16, |
562 Node* offset = assembler->IntPtrAdd(var_offset.value(), | 511 two_byte_result, max_index_offset, code16); |
563 assembler->IntPtrConstant(1)); | 512 max_index.Bind( |
| 513 assembler->IntPtrAdd(max_index.value(), assembler->IntPtrConstant(1))); |
564 | 514 |
565 // Check if we're done with the string. | 515 // Resume copying the passed-in arguments from the same place where the |
566 assembler->GotoIf(assembler->WordEqual(offset, length), &done_floop); | 516 // 8-bit copy stopped, but this time copying over all of the characters |
567 | 517 // using a 16-bit representation. |
568 // Load the next code point and truncate it to a 16-bit value. | 518 arguments.ForEach( |
569 Node* code = assembler->Load( | 519 vars, |
570 MachineType::AnyTagged(), parent_frame_pointer, | 520 [context, two_byte_result, &max_index](CodeStubAssembler* assembler, |
571 assembler->IntPtrAdd( | 521 Node* arg) { |
572 assembler->WordShl( | 522 Node* code32 = assembler->TruncateTaggedToWord32(context, arg); |
573 assembler->IntPtrSub(length, offset), | |
574 assembler->IntPtrConstant(kPointerSizeLog2)), | |
575 assembler->IntPtrConstant( | |
576 CommonFrameConstants::kFixedFrameSizeAboveFp - | |
577 kPointerSize))); | |
578 Node* code32 = assembler->TruncateTaggedToWord32(context, code); | |
579 Node* code16 = assembler->Word32And( | 523 Node* code16 = assembler->Word32And( |
580 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); | 524 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); |
581 | 525 |
582 // Store the truncated {code} point at the next offset. | 526 Node* offset = assembler->ElementOffsetFromIndex( |
583 assembler->StoreNoWriteBarrier( | 527 max_index.value(), UINT16_ELEMENTS, |
584 MachineRepresentation::kWord16, cresult, | 528 CodeStubAssembler::INTPTR_PARAMETERS, |
585 assembler->IntPtrAdd( | 529 SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
586 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | 530 assembler->StoreNoWriteBarrier(MachineRepresentation::kWord16, |
587 kHeapObjectTag), | 531 two_byte_result, offset, code16); |
588 assembler->WordShl(offset, 1)), | 532 max_index.Bind(assembler->IntPtrAdd(max_index.value(), |
589 code16); | 533 assembler->IntPtrConstant(1))); |
590 var_offset.Bind(offset); | 534 }, |
591 assembler->Goto(&floop); | 535 max_index.value()); |
592 } | |
593 | 536 |
594 // Return the SeqTwoByteString. | 537 arguments.PopAndReturn(two_byte_result); |
595 assembler->Bind(&done_floop); | |
596 assembler->Return(cresult); | |
597 } | |
598 } | |
599 | |
600 assembler->Bind(&done_loop); | |
601 assembler->Return(result); | |
602 } | 538 } |
603 } | 539 } |
604 | 540 |
605 namespace { // for String.fromCodePoint | 541 namespace { // for String.fromCodePoint |
606 | 542 |
607 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { | 543 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { |
608 if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) { | 544 if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) { |
609 return false; | 545 return false; |
610 } | 546 } |
611 | 547 |
(...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1491 Runtime::kThrowIncompatibleMethodReceiver, context, | 1427 Runtime::kThrowIncompatibleMethodReceiver, context, |
1492 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | 1428 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( |
1493 "String Iterator.prototype.next", TENURED)), | 1429 "String Iterator.prototype.next", TENURED)), |
1494 iterator); | 1430 iterator); |
1495 assembler->Return(result); // Never reached. | 1431 assembler->Return(result); // Never reached. |
1496 } | 1432 } |
1497 } | 1433 } |
1498 | 1434 |
1499 } // namespace internal | 1435 } // namespace internal |
1500 } // namespace v8 | 1436 } // namespace v8 |
OLD | NEW |