| 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 |