diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc index 7aba998aa4..2787b659c1 100644 --- a/src/builtins/builtins-string.cc +++ b/src/builtins/builtins-string.cc @@ -109,6 +109,7 @@ BUILTIN(StringFromCodePoint) { isolate->factory()->NewRawTwoByteString( static_cast(one_byte_buffer.size() + two_byte_buffer.size()))); + DisallowHeapAllocation no_gc; CopyChars(result->GetChars(), one_byte_buffer.data(), one_byte_buffer.size()); CopyChars(result->GetChars() + one_byte_buffer.size(), two_byte_buffer.data(), two_byte_buffer.size()); @@ -467,6 +468,7 @@ V8_WARN_UNUSED_RESULT static Object* ConvertCase( String::FlatContent flat_content = s->GetFlatContent(); DCHECK(flat_content.IsFlat()); bool has_changed_character = false; + DisallowHeapAllocation no_gc; int index_to_first_unprocessed = FastAsciiConvert( reinterpret_cast(result->GetChars()), reinterpret_cast(flat_content.ToOneByteVector().start()), diff --git a/src/builtins/builtins-trace.cc b/src/builtins/builtins-trace.cc index c2b799412f..7df5f2f348 100644 --- a/src/builtins/builtins-trace.cc +++ b/src/builtins/builtins-trace.cc @@ -34,6 +34,7 @@ class MaybeUtf8 { // Why copy? Well, the trace event mechanism requires null-terminated // strings, the bytes we get from SeqOneByteString are not. buf_ is // guaranteed to be null terminated. + DisallowHeapAllocation no_gc; memcpy(buf_, Handle::cast(string)->GetChars(), len); } } else { diff --git a/src/heap/factory.cc b/src/heap/factory.cc index ab25cf5fd5..0666670529 100644 --- a/src/heap/factory.cc +++ b/src/heap/factory.cc @@ -664,6 +664,7 @@ MaybeHandle Factory::NewStringFromUtf8(Vector string, NewRawTwoByteString(non_ascii_start + utf16_length, pretenure), String); // Copy ASCII portion. + DisallowHeapAllocation no_gc; uint16_t* data = result->GetChars(); for (int i = 0; i < non_ascii_start; i++) { *data++ = *ascii_data++; @@ -677,23 +678,31 @@ MaybeHandle Factory::NewStringFromUtf8(Vector string, MaybeHandle Factory::NewStringFromUtf8SubString( Handle str, int begin, int length, PretenureFlag pretenure) { - const char* ascii_data = - reinterpret_cast(str->GetChars() + begin); - int non_ascii_start = String::NonAsciiStart(ascii_data, length); + Access decoder( + isolate()->unicode_cache()->utf8_decoder()); + int non_ascii_start; + int utf16_length = 0; + { + DisallowHeapAllocation no_gc; + const char* ascii_data = + reinterpret_cast(str->GetChars() + begin); + non_ascii_start = String::NonAsciiStart(ascii_data, length); + if (non_ascii_start < length) { + // Non-ASCII and we need to decode. + auto non_ascii = Vector(ascii_data + non_ascii_start, + length - non_ascii_start); + decoder->Reset(non_ascii); + + utf16_length = static_cast(decoder->Utf16Length()); + } + } + if (non_ascii_start >= length) { // If the string is ASCII, we can just make a substring. // TODO(v8): the pretenure flag is ignored in this case. return NewSubString(str, begin, begin + length); } - // Non-ASCII and we need to decode. - auto non_ascii = Vector(ascii_data + non_ascii_start, - length - non_ascii_start); - Access decoder( - isolate()->unicode_cache()->utf8_decoder()); - decoder->Reset(non_ascii); - - int utf16_length = static_cast(decoder->Utf16Length()); DCHECK_GT(utf16_length, 0); // Allocate string. @@ -704,9 +713,11 @@ MaybeHandle Factory::NewStringFromUtf8SubString( // Update pointer references, since the original string may have moved after // allocation. - ascii_data = reinterpret_cast(str->GetChars() + begin); - non_ascii = Vector(ascii_data + non_ascii_start, - length - non_ascii_start); + DisallowHeapAllocation no_gc; + const char* ascii_data = + reinterpret_cast(str->GetChars() + begin); + auto non_ascii = Vector(ascii_data + non_ascii_start, + length - non_ascii_start); // Copy ASCII portion. uint16_t* data = result->GetChars(); @@ -728,12 +739,14 @@ MaybeHandle Factory::NewStringFromTwoByte(const uc16* string, Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, NewRawOneByteString(length, pretenure), String); + DisallowHeapAllocation no_gc; CopyChars(result->GetChars(), string, length); return result; } else { Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, NewRawTwoByteString(length, pretenure), String); + DisallowHeapAllocation no_gc; CopyChars(result->GetChars(), string, length); return result; } @@ -828,6 +841,7 @@ Handle Factory::AllocateTwoByteInternalizedString( answer->set_length(str.length()); answer->set_hash_field(hash_field); DCHECK_EQ(size, answer->Size()); + DisallowHeapAllocation no_gc; // Fill in the characters. MemCopy(answer->GetChars(), str.start(), str.length() * kUC16Size); @@ -861,6 +875,7 @@ Handle Factory::AllocateInternalizedStringImpl(T t, int chars, answer->set_length(chars); answer->set_hash_field(hash_field); DCHECK_EQ(size, answer->Size()); + DisallowHeapAllocation no_gc; if (is_one_byte) { WriteOneByteData(t, SeqOneByteString::cast(*answer)->GetChars(), chars); @@ -876,6 +891,7 @@ Handle Factory::NewInternalizedStringFromUtf8(Vector str, if (IsOneByte(str, chars)) { Handle result = AllocateRawOneByteInternalizedString(str.length(), hash_field); + DisallowHeapAllocation no_allocation; MemCopy(result->GetChars(), str.start(), str.length()); return result; } @@ -886,6 +902,7 @@ Handle Factory::NewOneByteInternalizedString(Vector str, uint32_t hash_field) { Handle result = AllocateRawOneByteInternalizedString(str.length(), hash_field); + DisallowHeapAllocation no_allocation; MemCopy(result->GetChars(), str.start(), str.length()); return result; } @@ -895,6 +912,7 @@ Handle Factory::NewOneByteInternalizedSubString( uint32_t hash_field) { Handle result = AllocateRawOneByteInternalizedString(length, hash_field); + DisallowHeapAllocation no_allocation; MemCopy(result->GetChars(), string->GetChars() + offset, length); return result; } @@ -1052,6 +1070,7 @@ static inline Handle MakeOrFindTwoCharacterString(Isolate* isolate, 1)); // because of this. Handle str = isolate->factory()->NewRawOneByteString(2).ToHandleChecked(); + DisallowHeapAllocation no_allocation; uint8_t* dest = str->GetChars(); dest[0] = static_cast(c1); dest[1] = static_cast(c2); @@ -1059,6 +1078,7 @@ static inline Handle MakeOrFindTwoCharacterString(Isolate* isolate, } else { Handle str = isolate->factory()->NewRawTwoByteString(2).ToHandleChecked(); + DisallowHeapAllocation no_allocation; uc16* dest = str->GetChars(); dest[0] = c1; dest[1] = c2; @@ -1188,6 +1208,7 @@ Handle Factory::NewSurrogatePairString(uint16_t lead, uint16_t trail) { Handle str = isolate()->factory()->NewRawTwoByteString(2).ToHandleChecked(); + DisallowHeapAllocation no_allocation; uc16* dest = str->GetChars(); dest[0] = lead; dest[1] = trail; @@ -1221,15 +1242,15 @@ Handle Factory::NewProperSubString(Handle str, int begin, if (str->IsOneByteRepresentation()) { Handle result = NewRawOneByteString(length).ToHandleChecked(); - uint8_t* dest = result->GetChars(); DisallowHeapAllocation no_gc; + uint8_t* dest = result->GetChars(); String::WriteToFlat(*str, dest, begin, end); return result; } else { Handle result = NewRawTwoByteString(length).ToHandleChecked(); - uc16* dest = result->GetChars(); DisallowHeapAllocation no_gc; + uc16* dest = result->GetChars(); String::WriteToFlat(*str, dest, begin, end); return result; } diff --git a/src/json-parser.cc b/src/json-parser.cc index c58987a971..0b7092088f 100644 --- a/src/json-parser.cc +++ b/src/json-parser.cc @@ -667,6 +667,7 @@ Handle JsonParser::ParseJsonNumber() { int length = position_ - beg_pos; double number; if (seq_one_byte) { + DisallowHeapAllocation no_gc; Vector chars(seq_source_->GetChars() + beg_pos, length); number = StringToDouble(chars, NO_FLAGS, // Hex, octal or trailing junk. @@ -726,9 +727,13 @@ Handle JsonParser::SlowScanJsonString( int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count)); Handle seq_string = NewRawString(factory(), length, pretenure_); - // Copy prefix into seq_str. - SinkChar* dest = seq_string->GetChars(); - String::WriteToFlat(*prefix, dest, start, end); + + { + DisallowHeapAllocation no_gc; + // Copy prefix into seq_str. + SinkChar* dest = seq_string->GetChars(); + String::WriteToFlat(*prefix, dest, start, end); + } while (c0_ != '"') { // Check for control character (0x00-0x1F) or unterminated string (<0). @@ -879,8 +884,6 @@ Handle JsonParser::ScanJsonString() { } else { hash = static_cast(length); } - Vector string_vector(seq_source_->GetChars() + position_, - length); StringTable string_table = isolate()->heap()->string_table(); uint32_t capacity = string_table->Capacity(); uint32_t entry = StringTable::FirstProbe(hash, capacity); @@ -894,12 +897,16 @@ Handle JsonParser::ScanJsonString() { factory()->InternalizeOneByteString(seq_source_, position_, length); break; } - if (!element->IsTheHole(isolate()) && - String::cast(element)->IsOneByteEqualTo(string_vector)) { - result = Handle(String::cast(element), isolate()); - DCHECK_EQ(result->Hash(), - (hash << String::kHashShift) >> String::kHashShift); - break; + if (!element->IsTheHole(isolate())) { + DisallowHeapAllocation no_gc; + Vector string_vector(seq_source_->GetChars() + position_, + length); + if (String::cast(element)->IsOneByteEqualTo(string_vector)) { + result = Handle(String::cast(element), isolate()); + DCHECK_EQ(result->Hash(), + (hash << String::kHashShift) >> String::kHashShift); + break; + } } entry = StringTable::NextProbe(entry, count++, capacity); } @@ -929,6 +936,7 @@ Handle JsonParser::ScanJsonString() { int length = position_ - beg_pos; Handle result = factory()->NewRawOneByteString(length, pretenure_).ToHandleChecked(); + DisallowHeapAllocation no_gc; uint8_t* dest = SeqOneByteString::cast(*result)->GetChars(); String::WriteToFlat(*source_, dest, beg_pos, position_); diff --git a/src/objects.cc b/src/objects.cc index 7964f4ed95..880bb4a9e2 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -11382,6 +11382,7 @@ void String::WriteToFlat(String* src, sinkchar* sink, int f, int t) { + DisallowHeapAllocation no_gc; String* source = src; int from = f; int to = t; @@ -12361,6 +12362,7 @@ bool String::IsTwoByteEqualTo(Vector str) { } uint32_t String::ComputeAndSetHash(Isolate* isolate) { + DisallowHeapAllocation no_gc; // Should only be called if hash code has not yet been computed. DCHECK(!HasHashCode()); @@ -12386,6 +12388,7 @@ bool String::ComputeArrayIndex(uint32_t* index) { bool String::SlowAsArrayIndex(uint32_t* index) { + DisallowHeapAllocation no_gc; if (length() <= kMaxCachedArrayIndexLength) { Hash(); // force computation of hash code uint32_t field = hash_field(); @@ -16751,6 +16754,7 @@ Handle SeqOneByteSubStringKey::AsHandle(Isolate* isolate) { bool SeqOneByteSubStringKey::IsMatch(Object* string) { + DisallowHeapAllocation no_gc; Vector chars(string_->GetChars() + from_, length_); return String::cast(string)->IsOneByteEqualTo(chars); } diff --git a/src/objects/string-inl.h b/src/objects/string-inl.h index 31702fe61a..67b1f639d6 100644 --- a/src/objects/string-inl.h +++ b/src/objects/string-inl.h @@ -239,11 +239,13 @@ class SeqOneByteSubStringKey : public StringTableKey { #endif SeqOneByteSubStringKey(Isolate* isolate, Handle string, int from, int length) - : StringTableKey(StringHasher::HashSequentialString( - string->GetChars() + from, length, isolate->heap()->HashSeed())), - string_(string), - from_(from), - length_(length) { + : StringTableKey(0), string_(string), from_(from), length_(length) { + // We have to set the hash later. + DisallowHeapAllocation no_gc; + uint32_t hash = StringHasher::HashSequentialString( + string->GetChars() + from, length, isolate->heap()->HashSeed()); + set_hash_field(hash); + DCHECK_LE(0, length_); DCHECK_LE(from_ + length_, string_->length()); DCHECK(string_->IsSeqOneByteString()); @@ -384,6 +386,7 @@ String* String::GetUnderlying() { template ConsString* String::VisitFlat(Visitor* visitor, String* string, const int offset) { + DisallowHeapAllocation no_gc; int slice_offset = offset; const int length = string->length(); DCHECK(offset <= length); @@ -474,6 +477,7 @@ Address SeqOneByteString::GetCharsAddress() { } uint8_t* SeqOneByteString::GetChars() { + DCHECK(!AllowHeapAllocation::IsAllowed()); return reinterpret_cast(GetCharsAddress()); } @@ -482,6 +486,7 @@ Address SeqTwoByteString::GetCharsAddress() { } uc16* SeqTwoByteString::GetChars() { + DCHECK(!AllowHeapAllocation::IsAllowed()); return reinterpret_cast(FIELD_ADDR(this, kHeaderSize)); } diff --git a/src/parsing/scanner-character-streams.cc b/src/parsing/scanner-character-streams.cc index 8472e9f4fc..6744707b31 100644 --- a/src/parsing/scanner-character-streams.cc +++ b/src/parsing/scanner-character-streams.cc @@ -257,6 +257,7 @@ class BufferedCharacterStream : public Utf16CharacterStream { buffer_start_ = &buffer_[0]; buffer_cursor_ = buffer_start_; + DisallowHeapAllocation no_gc; Range range = byte_stream_.GetDataAt(position, runtime_call_stats()); if (range.length() == 0) { @@ -310,6 +311,7 @@ class UnbufferedCharacterStream : public Utf16CharacterStream { bool ReadBlock() final { size_t position = pos(); buffer_pos_ = position; + DisallowHeapAllocation no_gc; Range range = byte_stream_.GetDataAt(position, runtime_call_stats()); buffer_start_ = range.start; diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc index eaed1df593..d8adb8f623 100644 --- a/src/regexp/regexp-macro-assembler.cc +++ b/src/regexp/regexp-macro-assembler.cc @@ -154,6 +154,7 @@ int NativeRegExpMacroAssembler::CheckStackGuardState( Isolate* isolate, int start_index, bool is_direct_call, Address* return_address, Code re_code, String** subject, const byte** input_start, const byte** input_end) { + AllowHeapAllocation allow_allocation; DCHECK(re_code->raw_instruction_start() <= *return_address); DCHECK(*return_address <= re_code->raw_instruction_end()); int return_value = 0; @@ -249,6 +250,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match( // String is now either Sequential or External int char_size_shift = is_one_byte ? 0 : 1; + DisallowHeapAllocation no_gc; const byte* input_start = StringCharacterPosition(subject_ptr, start_offset + slice_offset); int byte_length = char_length << char_size_shift; @@ -287,7 +289,10 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute( if (result == EXCEPTION && !isolate->has_pending_exception()) { // We detected a stack overflow (on the backtrack stack) in RegExp code, - // but haven't created the exception yet. + // but haven't created the exception yet. Additionally, we allow heap + // allocation because even though it invalidates {input_start} and + // {input_end}, we are about to return anyway. + AllowHeapAllocation allow_allocation; isolate->StackOverflow(); } return static_cast(result); diff --git a/src/runtime/runtime-regexp.cc b/src/runtime/runtime-regexp.cc index 403a7ce34d..583388540e 100644 --- a/src/runtime/runtime-regexp.cc +++ b/src/runtime/runtime-regexp.cc @@ -570,6 +570,7 @@ V8_WARN_UNUSED_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res); Handle result = Handle::cast(untyped_res); + DisallowHeapAllocation no_gc; for (int index : *indices) { // Copy non-matched subject content. if (subject_pos < index) { @@ -739,6 +740,7 @@ V8_WARN_UNUSED_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( int prev = 0; int position = 0; + DisallowHeapAllocation no_gc; do { start = current_match[0]; end = current_match[1]; diff --git a/src/runtime/runtime-strings.cc b/src/runtime/runtime-strings.cc index 9a5d5c0bea..479fdd8d45 100644 --- a/src/runtime/runtime-strings.cc +++ b/src/runtime/runtime-strings.cc @@ -327,6 +327,7 @@ RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { Handle answer; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, answer, isolate->factory()->NewRawOneByteString(length)); + DisallowHeapAllocation no_gc; StringBuilderConcatHelper(*special, answer->GetChars(), FixedArray::cast(array->elements()), array_length); @@ -335,6 +336,7 @@ RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { Handle answer; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, answer, isolate->factory()->NewRawTwoByteString(length)); + DisallowHeapAllocation no_gc; StringBuilderConcatHelper(*special, answer->GetChars(), FixedArray::cast(array->elements()), array_length); @@ -552,6 +554,7 @@ RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) { Handle result = isolate->factory() ->NewRawOneByteString(string_length) .ToHandleChecked(); + DisallowHeapAllocation no_gc; JoinSparseArrayWithSeparator( FixedArray::cast(elements_array->elements()), elements_length, array_length, *separator, @@ -561,6 +564,7 @@ RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) { Handle result = isolate->factory() ->NewRawTwoByteString(string_length) .ToHandleChecked(); + DisallowHeapAllocation no_gc; JoinSparseArrayWithSeparator( FixedArray::cast(elements_array->elements()), elements_length, array_length, *separator, diff --git a/src/uri.cc b/src/uri.cc index 34fde85f17..f5bffbacb7 100644 --- a/src/uri.cc +++ b/src/uri.cc @@ -194,6 +194,7 @@ MaybeHandle Uri::Decode(Isolate* isolate, Handle uri, isolate, result, isolate->factory()->NewRawTwoByteString(result_length), String); + DisallowHeapAllocation no_gc; CopyChars(result->GetChars(), one_byte_buffer.data(), one_byte_buffer.size()); CopyChars(result->GetChars() + one_byte_buffer.size(), two_byte_buffer.data(), two_byte_buffer.size()); diff --git a/src/value-serializer.cc b/src/value-serializer.cc index 34a970597c..51ecca024c 100644 --- a/src/value-serializer.cc +++ b/src/value-serializer.cc @@ -1336,6 +1336,7 @@ MaybeHandle ValueDeserializer::ReadTwoByteString() { // Copy the bytes directly into the new string. // Warning: this uses host endianness. + DisallowHeapAllocation no_gc; memcpy(string->GetChars(), bytes.begin(), bytes.length()); return string; } diff --git a/test/cctest/test-code-stub-assembler.cc b/test/cctest/test-code-stub-assembler.cc index d86649614e..6db2eed145 100644 --- a/test/cctest/test-code-stub-assembler.cc +++ b/test/cctest/test-code-stub-assembler.cc @@ -1787,6 +1787,7 @@ TEST(OneToTwoByteStringCopy) { isolate->factory()->NewStringFromTwoByte(str).ToHandleChecked(); FunctionTester ft(asm_tester.GenerateCode(), kNumParams); ft.Call(string1, string2); + DisallowHeapAllocation no_gc; CHECK_EQ(Handle::cast(string1)->GetChars()[0], Handle::cast(string2)->GetChars()[0]); CHECK_EQ(Handle::cast(string1)->GetChars()[1], @@ -1818,6 +1819,7 @@ TEST(OneToOneByteStringCopy) { isolate->factory()->NewStringFromOneByte(str).ToHandleChecked(); FunctionTester ft(asm_tester.GenerateCode(), kNumParams); ft.Call(string1, string2); + DisallowHeapAllocation no_gc; CHECK_EQ(Handle::cast(string1)->GetChars()[0], Handle::cast(string2)->GetChars()[0]); CHECK_EQ(Handle::cast(string1)->GetChars()[1], @@ -1849,6 +1851,7 @@ TEST(OneToOneByteStringCopyNonZeroStart) { isolate->factory()->NewStringFromOneByte(str).ToHandleChecked(); FunctionTester ft(asm_tester.GenerateCode(), kNumParams); ft.Call(string1, string2); + DisallowHeapAllocation no_gc; CHECK_EQ(Handle::cast(string1)->GetChars()[0], Handle::cast(string2)->GetChars()[3]); CHECK_EQ(Handle::cast(string1)->GetChars()[1], @@ -1880,6 +1883,7 @@ TEST(TwoToTwoByteStringCopy) { isolate->factory()->NewStringFromTwoByte(str2).ToHandleChecked(); FunctionTester ft(asm_tester.GenerateCode(), kNumParams); ft.Call(string1, string2); + DisallowHeapAllocation no_gc; CHECK_EQ(Handle::cast(string1)->GetChars()[0], Handle::cast(string2)->GetChars()[0]); CHECK_EQ(Handle::cast(string1)->GetChars()[1], diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc index 80093dc4e2..b6056065e3 100644 --- a/test/cctest/test-strings.cc +++ b/test/cctest/test-strings.cc @@ -1819,6 +1819,7 @@ TEST(Regress876759) { { Handle raw = factory->NewRawTwoByteString(kLength).ToHandleChecked(); + DisallowHeapAllocation no_gc; CopyChars(raw->GetChars(), two_byte_buf, kLength); parent = raw; }