Chromium Code Reviews| Index: src/builtins/builtins-string.cc |
| diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc |
| index 640e425d23e47b6678af913a5da40d04ab055dc5..83d2a94bceb5bedfbc98beb2718a7b850a2be3c1 100644 |
| --- a/src/builtins/builtins-string.cc |
| +++ b/src/builtins/builtins-string.cc |
| @@ -616,58 +616,545 @@ void Builtins::Generate_StringPrototypeValueOf(CodeStubAssembler* assembler) { |
| assembler->Return(result); |
| } |
| -BUILTIN(StringPrototypeIterator) { |
| - HandleScope scope(isolate); |
| - TO_THIS_STRING(object, "String.prototype[Symbol.iterator]"); |
| +void Builtins::Generate_StringPrototypeIterator(CodeStubAssembler* assembler) { |
| + typedef CodeStubAssembler::Label Label; |
| + typedef compiler::Node Node; |
| + typedef CodeStubAssembler::Variable Variable; |
| + |
| + Variable var_string(assembler, MachineRepresentation::kTagged); |
| + Variable var_index(assembler, MachineRepresentation::kWord32); |
| + |
| + Variable* loop_inputs[] = {&var_string, &var_index}; |
| + Label loop(assembler, 2, loop_inputs); |
| + Label allocate_iterator(assembler); |
| + |
| + Node* receiver = assembler->Parameter(0); |
| + Node* context = assembler->Parameter(3); |
| + |
| + Node* string = assembler->ToThisString(context, receiver, |
| + "String.prototype[Symbol.iterator]"); |
| + var_string.Bind(string); |
| + var_index.Bind(assembler->Int32Constant(0)); |
| + |
| + assembler->Goto(&loop); |
| + assembler->Bind(&loop); |
| + { |
| + // Load the instance type of the {string}. |
| + Node* string_instance_type = assembler->LoadInstanceType(string); |
| + |
| + // Check if the {string} is a SeqString. |
| + Label if_stringisnotsequential(assembler); |
| + assembler->Branch(assembler->Word32Equal( |
| + assembler->Word32And(string_instance_type, |
| + assembler->Int32Constant( |
| + kStringRepresentationMask)), |
| + assembler->Int32Constant(kSeqStringTag)), |
| + &allocate_iterator, &if_stringisnotsequential); |
| + |
| + assembler->Bind(&if_stringisnotsequential); |
| + { |
| + // Check if the {string} is a ConsString. |
| + Label if_stringiscons(assembler), if_stringisnotcons(assembler); |
| + assembler->Branch( |
| + assembler->Word32Equal( |
| + assembler->Word32And( |
| + string_instance_type, |
| + assembler->Int32Constant(kStringRepresentationMask)), |
| + assembler->Int32Constant(kConsStringTag)), |
| + &if_stringiscons, &if_stringisnotcons); |
| + |
| + assembler->Bind(&if_stringiscons); |
| + { |
| + // Flatten cons-string and finish. |
| + var_string.Bind(assembler->CallRuntime( |
| + Runtime::kFlattenString, assembler->NoContextConstant(), string)); |
| + assembler->Goto(&allocate_iterator); |
| + } |
| - Handle<String> string; |
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, |
| - Object::ToString(isolate, object)); |
| + assembler->Bind(&if_stringisnotcons); |
| + { |
| + // Check if the {string} is an ExternalString. |
| + Label if_stringisnotexternal(assembler); |
| + assembler->Branch( |
| + assembler->Word32Equal( |
| + assembler->Word32And( |
| + string_instance_type, |
| + assembler->Int32Constant(kStringRepresentationMask)), |
| + assembler->Int32Constant(kExternalStringTag)), |
| + &allocate_iterator, &if_stringisnotexternal); |
| + |
| + assembler->Bind(&if_stringisnotexternal); |
| + { |
| + // The {string} is a SlicedString, continue with its parent. |
| + Node* index = var_index.value(); |
| + Node* string_offset = assembler->LoadAndUntagObjectField( |
| + string, SlicedString::kOffsetOffset); |
| + Node* string_parent = |
| + assembler->LoadObjectField(string, SlicedString::kParentOffset); |
| + var_index.Bind(assembler->IntPtrAdd(index, string_offset)); |
| + var_string.Bind(string_parent); |
| + assembler->Goto(&loop); |
| + } |
| + } |
| + } |
| + } |
| - return *isolate->factory()->NewJSStringIterator(string); |
| + assembler->Bind(&allocate_iterator); |
| + { |
| + Node* native_context = assembler->LoadNativeContext(context); |
| + Node* index = assembler->Int32Constant(Context::STRING_ITERATOR_MAP_INDEX); |
| + Node* map = assembler->LoadFixedArrayElement( |
| + native_context, index, 0, CodeStubAssembler::INTPTR_PARAMETERS); |
| + Node* iterator = assembler->Allocate(JSStringIterator::kSize); |
| + assembler->StoreMapNoWriteBarrier(iterator, map); |
| + assembler->StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset, |
| + Heap::kEmptyFixedArrayRootIndex); |
| + assembler->StoreObjectFieldRoot(iterator, JSObject::kElementsOffset, |
| + Heap::kEmptyFixedArrayRootIndex); |
| + assembler->StoreObjectField(iterator, JSStringIterator::kStringOffset, |
|
Benedikt Meurer
2016/09/23 18:14:53
This doesn't need a write barrier, since the objec
caitp
2016/09/23 19:14:16
Done.
|
| + var_string.value()); |
| + |
| + assembler->StoreObjectField(iterator, JSStringIterator::kNextIndexOffset, |
|
Benedikt Meurer
2016/09/23 18:14:53
This doesn't need a write barrier, you can safely
caitp
2016/09/23 19:14:16
Done.
|
| + assembler->SmiFromWord32(var_index.value())); |
| + assembler->Return(iterator); |
| + } |
| } |
| -BUILTIN(StringIteratorPrototypeNext) { |
| - HandleScope scope(isolate); |
| +namespace { |
| - if (!args.receiver()->IsJSStringIterator()) { |
| - Handle<String> reason = isolate->factory()->NewStringFromAsciiChecked( |
| - "String Iterator.prototype.next"); |
| - THROW_NEW_ERROR_RETURN_FAILURE( |
| - isolate, |
| - NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, reason)); |
| +enum class UnicodeEncoding { |
| + UTF16, // high 16bits trail surrogate, low 16bits lead surrogate |
| + UTF32 |
| +}; |
| + |
| +// Return the |String| containing a single {codepoint}, which may be encoded |
| +// as one of the following: a single UTF16 code unit, a |word32| with the |
| +// high 16 bits set to the trailing surrogate, and low 16 bits set to the lead |
| +// surrogate, or a single UTF32-encoded codepoint. |
| +static compiler::Node* CreateStringFromCodePointInternal( |
|
Benedikt Meurer
2016/09/23 03:46:24
You don't need static inside an anonymous namespac
caitp
2016/09/23 10:14:28
The UnicodeEncoding thing is there to control how
caitp
2016/09/23 19:14:16
The UnicodeEncoding thing is there to control how
Benedikt Meurer
2016/09/26 04:15:40
Acknowledged.
|
| + CodeStubAssembler* assembler, compiler::Node* codepoint, |
| + UnicodeEncoding encoding) { |
| + typedef CodeStubAssembler::Label Label; |
| + typedef compiler::Node Node; |
| + typedef CodeStubAssembler::Variable Variable; |
| + |
| + Variable var_result(assembler, MachineRepresentation::kTagged); |
| + var_result.Bind(assembler->EmptyStringConstant()); |
| + |
| + Label if_isonebyte(assembler), if_istwobyte(assembler), |
| + return_result(assembler); |
| + |
| + assembler->Branch( |
| + assembler->Uint32LessThan(codepoint, assembler->Int32Constant(0x100)), |
| + &if_isonebyte, &if_istwobyte); |
| + |
| + assembler->Bind(&if_isonebyte); |
| + { |
| + Node* value = assembler->AllocateSeqOneByteString(1); |
| + assembler->StoreNoWriteBarrier( |
| + MachineRepresentation::kWord8, value, |
| + assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - |
| + kHeapObjectTag), |
| + codepoint); |
| + var_result.Bind(value); |
| + assembler->Goto(&return_result); |
| } |
| - Handle<JSStringIterator> iterator = |
| - Handle<JSStringIterator>::cast(args.receiver()); |
| - Handle<String> string(iterator->string()); |
| - |
| - int position = iterator->index(); |
| - int length = string->length(); |
| - |
| - if (position < length) { |
| - uint16_t lead = string->Get(position); |
| - if (lead >= 0xD800 && lead <= 0xDBFF && position + 1 < length) { |
| - uint16_t trail = string->Get(position + 1); |
| - if (V8_LIKELY(trail >= 0xDC00 && trail <= 0xDFFF)) { |
| - // Return surrogate pair code units |
| - iterator->set_index(position + 2); |
| - Handle<String> value = |
| - isolate->factory()->NewSurrogatePairString(lead, trail); |
| - return *isolate->factory()->NewJSIteratorResult(value, false); |
| + |
| + assembler->Bind(&if_istwobyte); |
| + { |
| + Label if_isdouble(assembler), if_issingle(assembler); |
| + assembler->Branch( |
| + assembler->Uint32LessThan(codepoint, assembler->Int32Constant(0x10000)), |
| + &if_issingle, &if_isdouble); |
| + |
| + assembler->Bind(&if_issingle); |
| + { |
| + Node* value = assembler->AllocateSeqTwoByteString(1); |
| + assembler->StoreNoWriteBarrier( |
| + MachineRepresentation::kWord16, value, |
| + assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| + kHeapObjectTag), |
| + codepoint); |
| + var_result.Bind(value); |
| + assembler->Goto(&return_result); |
| + } |
| + |
| + assembler->Bind(&if_isdouble); |
| + { |
| + switch (encoding) { |
| + case UnicodeEncoding::UTF16: |
| + break; |
| + case UnicodeEncoding::UTF32: { |
| + // Convert UTF32 to UTF16 code units, and store as a 32 bit word. |
| + Node* lead_offset = |
|
caitp
2016/09/23 19:14:16
This code here in particular should be very useful
|
| + assembler->Int32Constant(0xD800 - (0x10000 >> 10)); |
| + |
| + Node* lead = assembler->Int32Add( |
| + assembler->WordShr(codepoint, assembler->Int32Constant(10)), |
| + lead_offset); |
| + |
| + Node* trail = assembler->Int32Add( |
| + assembler->Word32And(codepoint, assembler->Int32Constant(0x3FF)), |
| + assembler->Int32Constant(0xDC00)); |
| + |
| + codepoint = assembler->Word32Or( |
| + assembler->WordShl(trail, assembler->Int32Constant(16)), lead); |
| + } |
| + default: |
| + UNREACHABLE(); |
| } |
| + |
| + Node* value = assembler->AllocateSeqTwoByteString(2); |
| + assembler->StoreNoWriteBarrier( |
| + MachineRepresentation::kWord32, value, |
| + assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| + kHeapObjectTag), |
| + codepoint); |
| + var_result.Bind(value); |
| + assembler->Goto(&return_result); |
| } |
| + } |
| + |
| + assembler->Bind(&return_result); |
| + return var_result.value(); |
| +} |
| - // Return single code unit |
| - iterator->set_index(position + 1); |
| - Handle<String> value = |
| - isolate->factory()->LookupSingleCharacterStringFromCode(lead); |
| - return *isolate->factory()->NewJSIteratorResult(value, false); |
| +static compiler::Node* CreateStringFromSurrogatePair( |
| + CodeStubAssembler* assembler, compiler::Node* code_units) { |
| + return CreateStringFromCodePointInternal(assembler, code_units, |
| + UnicodeEncoding::UTF16); |
| +} |
| + |
| +// Return the |word32| codepoint at {index}. Supports SeqStrings and |
| +// ExternalStrings. |
| +static compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler, |
| + compiler::Node* string, |
| + compiler::Node* length, |
| + compiler::Node* index, |
| + UnicodeEncoding encoding) { |
| + typedef CodeStubAssembler::Label Label; |
| + typedef compiler::Node Node; |
| + typedef CodeStubAssembler::Variable Variable; |
| + Label handle_surrogate_pair(assembler), return_result(assembler); |
| + Variable var_result(assembler, MachineRepresentation::kWord32); |
| + Variable var_trail(assembler, MachineRepresentation::kWord16); |
| + var_result.Bind(assembler->Int32Constant(0)); |
| + var_trail.Bind(assembler->Int32Constant(0)); |
| + |
| + Node* string_instance_type = assembler->LoadInstanceType(string); |
| + |
| + Label if_stringissequential(assembler), if_stringisexternal(assembler); |
| + assembler->Branch(assembler->Word32Equal( |
| + assembler->Word32And(string_instance_type, |
| + assembler->Int32Constant( |
| + kStringRepresentationMask)), |
| + assembler->Int32Constant(kSeqStringTag)), |
| + &if_stringissequential, &if_stringisexternal); |
| + |
| + assembler->Bind(&if_stringissequential); |
| + { |
| + Label if_stringisonebyte(assembler), if_stringistwobyte(assembler); |
| + assembler->Branch( |
| + assembler->Word32Equal( |
| + assembler->Word32And(string_instance_type, |
| + assembler->Int32Constant(kStringEncodingMask)), |
| + assembler->Int32Constant(kOneByteStringTag)), |
| + &if_stringisonebyte, &if_stringistwobyte); |
| + |
| + assembler->Bind(&if_stringisonebyte); |
| + { |
| + var_result.Bind(assembler->Load( |
| + MachineType::Uint8(), string, |
| + assembler->IntPtrAdd( |
| + index, assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - |
| + kHeapObjectTag)))); |
| + assembler->Goto(&return_result); |
| + } |
| + |
| + assembler->Bind(&if_stringistwobyte); |
| + { |
| + Node* lead = assembler->Load( |
| + MachineType::Uint16(), string, |
| + assembler->IntPtrAdd( |
| + assembler->WordShl(index, assembler->IntPtrConstant(1)), |
| + assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| + kHeapObjectTag))); |
| + var_result.Bind(lead); |
| + Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1)); |
| + |
| + Label if_isdoublecodeunit(assembler); |
| + assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), |
| + &return_result); |
| + assembler->GotoIf( |
| + assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), |
| + &return_result); |
| + assembler->Branch( |
| + assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)), |
| + &if_isdoublecodeunit, &return_result); |
| + |
| + assembler->Bind(&if_isdoublecodeunit); |
| + { |
| + Node* trail = assembler->Load( |
| + MachineType::Uint16(), string, |
| + assembler->IntPtrAdd( |
| + assembler->WordShl(next_pos, assembler->IntPtrConstant(1)), |
| + assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| + kHeapObjectTag))); |
| + assembler->GotoIf( |
| + assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)), |
| + &return_result); |
| + assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( |
| + trail, assembler->Int32Constant(0xE000)), |
| + &return_result); |
| + |
| + var_trail.Bind(trail); |
| + assembler->Goto(&handle_surrogate_pair); |
| + } |
| + } |
| } |
| - iterator->set_string(isolate->heap()->empty_string()); |
| + assembler->Bind(&if_stringisexternal); |
| + { |
| + assembler->Assert(assembler->Word32Equal( |
| + assembler->Word32And( |
| + string_instance_type, |
| + assembler->Int32Constant(kStringRepresentationMask)), |
| + assembler->Int32Constant(kExternalStringTag))); |
| + Label if_stringisshort(assembler), if_stringisnotshort(assembler); |
| + |
| + assembler->Branch(assembler->Word32Equal( |
| + assembler->Word32And(string_instance_type, |
| + assembler->Int32Constant( |
| + kShortExternalStringMask)), |
| + assembler->Int32Constant(0)), |
| + &if_stringisshort, &if_stringisnotshort); |
| + |
| + assembler->Bind(&if_stringisshort); |
| + { |
| + // Load the actual resource data from the {string}. |
| + Node* string_resource_data = assembler->LoadObjectField( |
| + string, ExternalString::kResourceDataOffset, MachineType::Pointer()); |
| + |
| + Label if_stringistwobyte(assembler), if_stringisonebyte(assembler); |
| + assembler->Branch(assembler->Word32Equal( |
| + assembler->Word32And( |
| + string_instance_type, |
| + assembler->Int32Constant(kStringEncodingMask)), |
| + assembler->Int32Constant(kTwoByteStringTag)), |
| + &if_stringistwobyte, &if_stringisonebyte); |
| + |
| + assembler->Bind(&if_stringisonebyte); |
| + { |
| + var_result.Bind( |
| + assembler->Load(MachineType::Uint8(), string_resource_data, index)); |
| + assembler->Goto(&return_result); |
| + } |
| + |
| + assembler->Bind(&if_stringistwobyte); |
| + { |
| + Label if_isdoublecodeunit(assembler); |
| + Node* lead = assembler->Load( |
| + MachineType::Uint16(), string_resource_data, |
| + assembler->WordShl(index, assembler->IntPtrConstant(1))); |
| + var_result.Bind(lead); |
| + Node* next_pos = |
| + assembler->Int32Add(index, assembler->Int32Constant(1)); |
| + |
| + assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), |
| + &return_result); |
| + assembler->GotoIf( |
| + assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), |
| + &return_result); |
| + assembler->Branch( |
| + assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00)), |
| + &if_isdoublecodeunit, &return_result); |
| + |
| + assembler->Bind(&if_isdoublecodeunit); |
| + { |
| + Node* trail = assembler->Load( |
| + MachineType::Uint16(), string, |
| + assembler->IntPtrAdd( |
| + assembler->WordShl(next_pos, assembler->IntPtrConstant(1)), |
| + assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| + kHeapObjectTag))); |
| + assembler->GotoIf(assembler->Uint32LessThan( |
| + trail, assembler->Int32Constant(0xDC00)), |
| + &return_result); |
| + assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( |
| + trail, assembler->Int32Constant(0xE000)), |
| + &return_result); |
| + |
| + var_trail.Bind(trail); |
| + assembler->Goto(&handle_surrogate_pair); |
| + } |
| + } |
| + } |
| + |
| + assembler->Bind(&if_stringisnotshort); |
| + { |
| + Label if_isdoublecodeunit(assembler); |
| + Node* lead = assembler->SmiToWord32(assembler->CallRuntime( |
| + Runtime::kExternalStringGetChar, assembler->NoContextConstant(), |
| + string, assembler->SmiTag(index))); |
| + var_result.Bind(lead); |
| + Node* next_pos = assembler->Int32Add(index, assembler->Int32Constant(1)); |
| + |
| + assembler->GotoIf(assembler->Int32GreaterThanOrEqual(next_pos, length), |
| + &return_result); |
| + assembler->GotoIf( |
| + assembler->Uint32LessThan(lead, assembler->Int32Constant(0xD800)), |
| + &return_result); |
| + assembler->Branch(assembler->Uint32GreaterThanOrEqual( |
| + lead, assembler->Int32Constant(0xDC00)), |
| + &return_result, &if_isdoublecodeunit); |
| + |
| + assembler->Bind(&if_isdoublecodeunit); |
| + { |
| + Node* trail = assembler->SmiToWord32(assembler->CallRuntime( |
| + Runtime::kExternalStringGetChar, assembler->NoContextConstant(), |
| + string, assembler->SmiTag(next_pos))); |
| + assembler->GotoIf( |
| + assembler->Uint32LessThan(trail, assembler->Int32Constant(0xDC00)), |
| + &return_result); |
| + assembler->GotoIf(assembler->Uint32GreaterThanOrEqual( |
| + trail, assembler->Int32Constant(0xE000)), |
| + &return_result); |
| + var_trail.Bind(trail); |
| + assembler->Goto(&handle_surrogate_pair); |
| + } |
| + } |
| + } |
| - return *isolate->factory()->NewJSIteratorResult( |
| - isolate->factory()->undefined_value(), true); |
| + assembler->Bind(&handle_surrogate_pair); |
| + { |
| + Node* lead = var_result.value(); |
| + Node* trail = var_trail.value(); |
| +#ifdef ENABLE_SLOW_DCHECKS |
| + // Check that this path is only taken if a surrogate pair is found |
| + assembler->Assert(assembler->Uint32GreaterThanOrEqual( |
| + lead, assembler->Int32Constant(0xD800))); |
| + assembler->Assert( |
| + assembler->Uint32LessThan(lead, assembler->Int32Constant(0xDC00))); |
| + assembler->Assert(assembler->Uint32GreaterThanOrEqual( |
| + trail, assembler->Int32Constant(0xDC00))); |
| + assembler->Assert( |
| + assembler->Uint32LessThan(trail, assembler->Int32Constant(0xE000))); |
| +#endif |
| + |
| + switch (encoding) { |
| + case UnicodeEncoding::UTF16: |
| + var_result.Bind(assembler->WordOr( |
| + assembler->WordShl(trail, assembler->Int32Constant(16)), lead)); |
| + break; |
| + |
| + case UnicodeEncoding::UTF32: { |
| + // Convert UTF16 surrogate pair into |word32| code point, encoded as |
| + // UTF32. |
| + Node* surrogate_offset = |
| + assembler->Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00); |
| + |
| + // (lead << 10) + trail + SURROGATE_OFFSET |
| + var_result.Bind(assembler->Int32Add( |
| + assembler->WordShl(lead, assembler->Int32Constant(10)), |
| + assembler->Int32Add(trail, surrogate_offset))); |
| + break; |
| + } |
| + } |
| + assembler->Goto(&return_result); |
| + } |
| + |
| + assembler->Bind(&return_result); |
| + return var_result.value(); |
| +} |
| + |
| +static compiler::Node* LoadSurrogatePairAt(CodeStubAssembler* assembler, |
| + compiler::Node* string, |
| + compiler::Node* length, |
| + compiler::Node* index) { |
| + return LoadSurrogatePairInternal(assembler, string, length, index, |
| + UnicodeEncoding::UTF16); |
| +} |
| + |
| +} // namespace |
| + |
| +void Builtins::Generate_StringIteratorPrototypeNext( |
| + CodeStubAssembler* assembler) { |
| + typedef CodeStubAssembler::Label Label; |
| + typedef compiler::Node Node; |
| + typedef CodeStubAssembler::Variable Variable; |
| + |
| + Variable var_value(assembler, MachineRepresentation::kTagged); |
| + Variable var_done(assembler, MachineRepresentation::kTagged); |
| + |
| + var_value.Bind(assembler->UndefinedConstant()); |
| + var_done.Bind(assembler->BooleanConstant(true)); |
| + |
| + Label throw_bad_receiver(assembler), next_codepoint(assembler), |
| + return_result(assembler); |
| + |
| + Node* iterator = assembler->Parameter(0); |
| + Node* context = assembler->Parameter(3); |
| + |
| + assembler->GotoIf(assembler->WordIsSmi(iterator), &throw_bad_receiver); |
| + assembler->GotoUnless( |
| + assembler->WordEqual(assembler->LoadInstanceType(iterator), |
| + assembler->Int32Constant(JS_STRING_ITERATOR_TYPE)), |
| + &throw_bad_receiver); |
| + |
| + Node* string = |
| + assembler->LoadObjectField(iterator, JSStringIterator::kStringOffset); |
| + Node* position = assembler->LoadAndUntagObjectField( |
| + iterator, JSStringIterator::kNextIndexOffset); |
| + Node* length = |
| + assembler->LoadAndUntagObjectField(string, String::kLengthOffset); |
| + |
| + assembler->Branch(assembler->Int32LessThan(position, length), &next_codepoint, |
| + &return_result); |
| + |
| + assembler->Bind(&next_codepoint); |
| + { |
| + Node* ch = LoadSurrogatePairAt(assembler, string, length, position); |
| + Node* value = CreateStringFromSurrogatePair(assembler, ch); |
| + var_value.Bind(value); |
| + Node* length = |
| + assembler->LoadAndUntagObjectField(value, String::kLengthOffset); |
| + assembler->StoreObjectFieldNoWriteBarrier( |
| + iterator, JSStringIterator::kNextIndexOffset, |
| + assembler->SmiFromWord32(assembler->Int32Add(position, length))); |
| + var_done.Bind(assembler->BooleanConstant(false)); |
| + assembler->Goto(&return_result); |
| + } |
| + |
| + assembler->Bind(&return_result); |
| + { |
| + Node* native_context = assembler->LoadNativeContext(context); |
| + Node* map = assembler->LoadFixedArrayElement( |
| + native_context, |
| + assembler->IntPtrConstant(Context::ITERATOR_RESULT_MAP_INDEX), 0, |
| + CodeStubAssembler::INTPTR_PARAMETERS); |
| + Node* result = assembler->Allocate(JSIteratorResult::kSize); |
| + assembler->StoreMapNoWriteBarrier(result, map); |
| + assembler->StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, |
| + Heap::kEmptyFixedArrayRootIndex); |
| + assembler->StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, |
| + Heap::kEmptyFixedArrayRootIndex); |
| + assembler->StoreObjectField(result, JSIteratorResult::kValueOffset, |
|
Benedikt Meurer
2016/09/23 18:14:53
You can skip write barrier for these two stores be
caitp
2016/09/23 19:14:16
Done.
|
| + var_value.value()); |
| + assembler->StoreObjectField(result, JSIteratorResult::kDoneOffset, |
| + var_done.value()); |
| + assembler->Return(result); |
| + } |
| + |
| + assembler->Bind(&throw_bad_receiver); |
| + { |
| + // The {receiver} is not a valid JSGeneratorObject. |
| + Node* result = assembler->CallRuntime( |
| + Runtime::kThrowIncompatibleMethodReceiver, context, |
| + assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( |
| + "String Iterator.prototype.next", TENURED)), |
| + iterator); |
| + assembler->Return(result); // Never reached. |
| + } |
| } |
| } // namespace internal |