Index: src/builtins/builtins-string.cc |
diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc |
index 7828dd231f1405874ee451211950f874c1562083..f210b8d9b4e666001a000d132a77c4ea35e0b096 100644 |
--- a/src/builtins/builtins-string.cc |
+++ b/src/builtins/builtins-string.cc |
@@ -424,181 +424,117 @@ void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { |
typedef compiler::Node Node; |
typedef CodeStubAssembler::Variable Variable; |
- Node* code = assembler->Parameter(1); |
- Node* context = assembler->Parameter(4); |
+ Node* argc = assembler->ChangeInt32ToIntPtr( |
+ assembler->Parameter(BuiltinDescriptor::kArgumentsCount)); |
+ Node* context = assembler->Parameter(BuiltinDescriptor::kContext); |
+ |
+ CodeStubArguments arguments(assembler, argc); |
// Check if we have exactly one argument (plus the implicit receiver), i.e. |
// if the parent frame is not an arguments adaptor frame. |
Label if_oneargument(assembler), if_notoneargument(assembler); |
- Node* parent_frame_pointer = assembler->LoadParentFramePointer(); |
- Node* parent_frame_type = |
- assembler->Load(MachineType::Pointer(), parent_frame_pointer, |
- assembler->IntPtrConstant( |
- CommonFrameConstants::kContextOrFrameTypeOffset)); |
- assembler->Branch( |
- assembler->WordEqual( |
- parent_frame_type, |
- assembler->SmiConstant(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))), |
- &if_notoneargument, &if_oneargument); |
+ assembler->Branch(assembler->WordEqual(argc, assembler->IntPtrConstant(1)), |
+ &if_oneargument, &if_notoneargument); |
assembler->Bind(&if_oneargument); |
{ |
// Single argument case, perform fast single character string cache lookup |
// for one-byte code units, or fall back to creating a single character |
// string on the fly otherwise. |
+ Node* code = arguments.AtIndex(0); |
Node* code32 = assembler->TruncateTaggedToWord32(context, code); |
Node* code16 = assembler->Word32And( |
code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); |
Node* result = assembler->StringFromCharCode(code16); |
- assembler->Return(result); |
+ arguments.PopAndReturn(result); |
} |
+ Node* code16 = nullptr; |
assembler->Bind(&if_notoneargument); |
{ |
- // Determine the resulting string length. |
- Node* length = assembler->LoadAndUntagSmi( |
- parent_frame_pointer, ArgumentsAdaptorFrameConstants::kLengthOffset); |
- |
+ Label two_byte(assembler); |
// Assume that the resulting string contains only one-byte characters. |
- Node* result = assembler->AllocateSeqOneByteString(context, length); |
- |
- // Truncate all input parameters and append them to the resulting string. |
- Variable var_offset(assembler, MachineType::PointerRepresentation()); |
- Label loop(assembler, &var_offset), done_loop(assembler); |
- var_offset.Bind(assembler->IntPtrConstant(0)); |
- assembler->Goto(&loop); |
- assembler->Bind(&loop); |
- { |
- // Load the current {offset}. |
- Node* offset = var_offset.value(); |
- |
- // Check if we're done with the string. |
- assembler->GotoIf(assembler->WordEqual(offset, length), &done_loop); |
- |
- // Load the next code point and truncate it to a 16-bit value. |
- Node* code = assembler->Load( |
- MachineType::AnyTagged(), parent_frame_pointer, |
- assembler->IntPtrAdd( |
- assembler->WordShl(assembler->IntPtrSub(length, offset), |
- assembler->IntPtrConstant(kPointerSizeLog2)), |
- assembler->IntPtrConstant( |
- CommonFrameConstants::kFixedFrameSizeAboveFp - |
- kPointerSize))); |
- Node* code32 = assembler->TruncateTaggedToWord32(context, code); |
- Node* code16 = assembler->Word32And( |
+ Node* one_byte_result = assembler->AllocateSeqOneByteString(context, argc); |
+ |
+ Variable max_index(assembler, MachineType::PointerRepresentation()); |
+ max_index.Bind(assembler->IntPtrConstant(0)); |
+ |
+ // Iterate over the incoming arguments, converting them to 8-bit character |
+ // codes. Stop if any of the conversions generates a code that doesn't fit |
+ // in 8 bits. |
+ CodeStubAssembler::VariableList vars({&max_index}, assembler->zone()); |
+ arguments.ForEach(vars, [context, &two_byte, &max_index, &code16, |
+ one_byte_result](CodeStubAssembler* assembler, |
+ Node* arg) { |
+ Node* code32 = assembler->TruncateTaggedToWord32(context, arg); |
+ code16 = assembler->Word32And( |
code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); |
- // Check if {code16} fits into a one-byte string. |
- Label if_codeisonebyte(assembler), if_codeistwobyte(assembler); |
- assembler->Branch( |
- assembler->Int32LessThanOrEqual( |
+ assembler->GotoIf( |
+ assembler->Int32GreaterThan( |
code16, assembler->Int32Constant(String::kMaxOneByteCharCode)), |
- &if_codeisonebyte, &if_codeistwobyte); |
- |
- assembler->Bind(&if_codeisonebyte); |
- { |
- // The {code16} fits into the SeqOneByteString {result}. |
- assembler->StoreNoWriteBarrier( |
- MachineRepresentation::kWord8, result, |
- assembler->IntPtrAdd( |
- assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - |
- kHeapObjectTag), |
- offset), |
- code16); |
- var_offset.Bind( |
- assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); |
- assembler->Goto(&loop); |
- } |
- |
- assembler->Bind(&if_codeistwobyte); |
- { |
- // Allocate a SeqTwoByteString to hold the resulting string. |
- Node* cresult = assembler->AllocateSeqTwoByteString(context, length); |
- |
- // Copy all characters that were previously written to the |
- // SeqOneByteString in {result} over to the new {cresult}. |
- Variable var_coffset(assembler, MachineType::PointerRepresentation()); |
- Label cloop(assembler, &var_coffset), done_cloop(assembler); |
- var_coffset.Bind(assembler->IntPtrConstant(0)); |
- assembler->Goto(&cloop); |
- assembler->Bind(&cloop); |
- { |
- Node* coffset = var_coffset.value(); |
- assembler->GotoIf(assembler->WordEqual(coffset, offset), &done_cloop); |
- Node* ccode = assembler->Load( |
- MachineType::Uint8(), result, |
- assembler->IntPtrAdd( |
- assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - |
- kHeapObjectTag), |
- coffset)); |
- assembler->StoreNoWriteBarrier( |
- MachineRepresentation::kWord16, cresult, |
- assembler->IntPtrAdd( |
- assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
- kHeapObjectTag), |
- assembler->WordShl(coffset, 1)), |
- ccode); |
- var_coffset.Bind( |
- assembler->IntPtrAdd(coffset, assembler->IntPtrConstant(1))); |
- assembler->Goto(&cloop); |
- } |
+ &two_byte); |
+ |
+ // The {code16} fits into the SeqOneByteString {one_byte_result}. |
+ Node* offset = assembler->ElementOffsetFromIndex( |
+ max_index.value(), UINT8_ELEMENTS, |
+ CodeStubAssembler::INTPTR_PARAMETERS, |
+ SeqOneByteString::kHeaderSize - kHeapObjectTag); |
+ assembler->StoreNoWriteBarrier(MachineRepresentation::kWord8, |
+ one_byte_result, offset, code16); |
+ max_index.Bind(assembler->IntPtrAdd(max_index.value(), |
+ assembler->IntPtrConstant(1))); |
+ }); |
+ arguments.PopAndReturn(one_byte_result); |
+ |
+ assembler->Bind(&two_byte); |
+ |
+ // At least one of the characters in the string requires a 16-bit |
+ // representation. Allocate a SeqTwoByteString to hold the resulting |
+ // string. |
+ Node* two_byte_result = assembler->AllocateSeqTwoByteString(context, argc); |
+ |
+ // Copy the characters that have already been put in the 8-bit string into |
+ // their corresponding positions in the new 16-bit string. |
+ Node* zero = assembler->IntPtrConstant(0); |
+ assembler->CopyStringCharacters( |
+ one_byte_result, two_byte_result, zero, zero, max_index.value(), |
+ String::ONE_BYTE_ENCODING, String::TWO_BYTE_ENCODING, |
+ CodeStubAssembler::INTPTR_PARAMETERS); |
- // Write the pending {code16} to {offset}. |
- assembler->Bind(&done_cloop); |
- assembler->StoreNoWriteBarrier( |
- MachineRepresentation::kWord16, cresult, |
- assembler->IntPtrAdd( |
- assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
- kHeapObjectTag), |
- assembler->WordShl(offset, 1)), |
- code16); |
- |
- // Copy the remaining parameters to the SeqTwoByteString {cresult}. |
- Label floop(assembler, &var_offset), done_floop(assembler); |
- assembler->Goto(&floop); |
- assembler->Bind(&floop); |
- { |
- // Compute the next {offset}. |
- Node* offset = assembler->IntPtrAdd(var_offset.value(), |
- assembler->IntPtrConstant(1)); |
- |
- // Check if we're done with the string. |
- assembler->GotoIf(assembler->WordEqual(offset, length), &done_floop); |
- |
- // Load the next code point and truncate it to a 16-bit value. |
- Node* code = assembler->Load( |
- MachineType::AnyTagged(), parent_frame_pointer, |
- assembler->IntPtrAdd( |
- assembler->WordShl( |
- assembler->IntPtrSub(length, offset), |
- assembler->IntPtrConstant(kPointerSizeLog2)), |
- assembler->IntPtrConstant( |
- CommonFrameConstants::kFixedFrameSizeAboveFp - |
- kPointerSize))); |
- Node* code32 = assembler->TruncateTaggedToWord32(context, code); |
+ // Write the character that caused the 8-bit to 16-bit fault. |
+ Node* max_index_offset = assembler->ElementOffsetFromIndex( |
+ max_index.value(), UINT16_ELEMENTS, |
+ CodeStubAssembler::INTPTR_PARAMETERS, |
+ SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
+ assembler->StoreNoWriteBarrier(MachineRepresentation::kWord16, |
+ two_byte_result, max_index_offset, code16); |
+ max_index.Bind( |
+ assembler->IntPtrAdd(max_index.value(), assembler->IntPtrConstant(1))); |
+ |
+ // Resume copying the passed-in arguments from the same place where the |
+ // 8-bit copy stopped, but this time copying over all of the characters |
+ // using a 16-bit representation. |
+ arguments.ForEach( |
+ vars, |
+ [context, two_byte_result, &max_index](CodeStubAssembler* assembler, |
+ Node* arg) { |
+ Node* code32 = assembler->TruncateTaggedToWord32(context, arg); |
Node* code16 = assembler->Word32And( |
code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); |
- // Store the truncated {code} point at the next offset. |
- assembler->StoreNoWriteBarrier( |
- MachineRepresentation::kWord16, cresult, |
- assembler->IntPtrAdd( |
- assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
- kHeapObjectTag), |
- assembler->WordShl(offset, 1)), |
- code16); |
- var_offset.Bind(offset); |
- assembler->Goto(&floop); |
- } |
- |
- // Return the SeqTwoByteString. |
- assembler->Bind(&done_floop); |
- assembler->Return(cresult); |
- } |
- } |
- |
- assembler->Bind(&done_loop); |
- assembler->Return(result); |
+ Node* offset = assembler->ElementOffsetFromIndex( |
+ max_index.value(), UINT16_ELEMENTS, |
+ CodeStubAssembler::INTPTR_PARAMETERS, |
+ SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
+ assembler->StoreNoWriteBarrier(MachineRepresentation::kWord16, |
+ two_byte_result, offset, code16); |
+ max_index.Bind(assembler->IntPtrAdd(max_index.value(), |
+ assembler->IntPtrConstant(1))); |
+ }, |
+ max_index.value()); |
+ |
+ arguments.PopAndReturn(two_byte_result); |
} |
} |