[regexp] Properly flatten string during initialization
This fixes an incorrect usage of String::Flatten in EscapeRegExpSource. It also adds %ConstructConsString (to easily and reliably construct cons strings in tests) and Factory::NewConsString (to enable guaranteed cons string construction without preemptive flattening attempts). BUG=chromium:698790 Review-Url: https://codereview.chromium.org/2736383003 Cr-Commit-Position: refs/heads/master@{#43686}
This commit is contained in:
parent
e9a25e287d
commit
5002a4a961
@ -711,10 +711,20 @@ MaybeHandle<String> Factory::NewConsString(Handle<String> left,
|
||||
NewRawTwoByteString(length).ToHandleChecked(), left, right);
|
||||
}
|
||||
|
||||
bool one_byte = (is_one_byte || is_one_byte_data_in_two_byte_string);
|
||||
return NewConsString(left, right, length, one_byte);
|
||||
}
|
||||
|
||||
Handle<String> Factory::NewConsString(Handle<String> left, Handle<String> right,
|
||||
int length, bool one_byte) {
|
||||
DCHECK(!left->IsThinString());
|
||||
DCHECK(!right->IsThinString());
|
||||
DCHECK_GE(length, ConsString::kMinLength);
|
||||
DCHECK_LE(length, String::kMaxLength);
|
||||
|
||||
Handle<ConsString> result =
|
||||
(is_one_byte || is_one_byte_data_in_two_byte_string)
|
||||
? New<ConsString>(cons_one_byte_string_map(), NEW_SPACE)
|
||||
: New<ConsString>(cons_string_map(), NEW_SPACE);
|
||||
one_byte ? New<ConsString>(cons_one_byte_string_map(), NEW_SPACE)
|
||||
: New<ConsString>(cons_string_map(), NEW_SPACE);
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
|
||||
|
@ -252,6 +252,10 @@ class V8_EXPORT_PRIVATE Factory final {
|
||||
MUST_USE_RESULT MaybeHandle<String> NewConsString(Handle<String> left,
|
||||
Handle<String> right);
|
||||
|
||||
MUST_USE_RESULT Handle<String> NewConsString(Handle<String> left,
|
||||
Handle<String> right, int length,
|
||||
bool one_byte);
|
||||
|
||||
// Create or lookup a single characters tring made up of a utf16 surrogate
|
||||
// pair.
|
||||
Handle<String> NewSurrogatePairString(uint16_t lead, uint16_t trail);
|
||||
|
@ -16111,7 +16111,7 @@ inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
|
||||
|
||||
MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
|
||||
Handle<String> source) {
|
||||
String::Flatten(source);
|
||||
DCHECK(source->IsFlat());
|
||||
if (source->length() == 0) return isolate->factory()->query_colon_string();
|
||||
bool one_byte = source->IsOneByteRepresentationUnderneath();
|
||||
int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
|
||||
@ -16160,6 +16160,8 @@ MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
|
||||
// suggested by ECMA-262, 5th, section 15.10.4.1.
|
||||
if (source->length() == 0) source = factory->query_colon_string();
|
||||
|
||||
source = String::Flatten(source);
|
||||
|
||||
Handle<String> escaped_source;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
|
||||
EscapeRegExpSource(isolate, source), JSRegExp);
|
||||
|
@ -135,6 +135,8 @@ static bool HasFewDifferentCharacters(Handle<String> pattern) {
|
||||
MaybeHandle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
|
||||
Handle<String> pattern,
|
||||
JSRegExp::Flags flags) {
|
||||
DCHECK(pattern->IsFlat());
|
||||
|
||||
Isolate* isolate = re->GetIsolate();
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
CompilationCache* compilation_cache = isolate->compilation_cache();
|
||||
@ -145,7 +147,7 @@ MaybeHandle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
|
||||
re->set_data(*cached);
|
||||
return re;
|
||||
}
|
||||
pattern = String::Flatten(pattern);
|
||||
|
||||
PostponeInterruptsScope postpone(isolate);
|
||||
RegExpCompileData parse_result;
|
||||
FlatStringReader reader(isolate, pattern);
|
||||
|
@ -71,6 +71,20 @@ RUNTIME_FUNCTION(Runtime_ConstructDouble) {
|
||||
return *isolate->factory()->NewNumber(uint64_to_double(result));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ConstructConsString) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(2, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, left, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, right, 1);
|
||||
|
||||
CHECK(left->IsOneByteRepresentation());
|
||||
CHECK(right->IsOneByteRepresentation());
|
||||
|
||||
const bool kIsOneByte = true;
|
||||
const int length = left->length() + right->length();
|
||||
return *isolate->factory()->NewConsString(left, right, length, kIsOneByte);
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
@ -549,6 +549,7 @@ namespace internal {
|
||||
|
||||
#define FOR_EACH_INTRINSIC_TEST(F) \
|
||||
F(ConstructDouble, 2, 1) \
|
||||
F(ConstructConsString, 2, 1) \
|
||||
F(DeoptimizeFunction, 1, 1) \
|
||||
F(DeoptimizeNow, 0, 1) \
|
||||
F(RunningInSimulator, 0, 1) \
|
||||
|
18
test/mjsunit/regress/regress-698790.js
Normal file
18
test/mjsunit/regress/regress-698790.js
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --turbo
|
||||
|
||||
// Call RegExp constructor with a cons string.
|
||||
|
||||
var cons_string = %ConstructConsString("", "aaaaaaaaaaaaaa");
|
||||
new RegExp(cons_string);
|
||||
|
||||
// Same thing but using TF lowering.
|
||||
|
||||
function make_cons_string(s) { return s + "aaaaaaaaaaaaaa"; }
|
||||
make_cons_string("");
|
||||
%OptimizeFunctionOnNextCall(make_cons_string);
|
||||
var cons_str = make_cons_string("");
|
||||
new RegExp(cons_str);
|
Loading…
Reference in New Issue
Block a user