v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
regexp-utils.cc
Go to the documentation of this file.
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
3// found in the LICENSE file.
4
6
9#include "src/heap/factory.h"
12#include "src/regexp/regexp.h"
13
14namespace v8 {
15namespace internal {
16
17// static
19 Isolate* isolate, DirectHandle<RegExpMatchInfo> match_info, int capture,
20 bool* ok) {
21 const int capture_start_index = RegExpMatchInfo::capture_start_index(capture);
22 if (capture_start_index >= match_info->number_of_capture_registers()) {
23 if (ok != nullptr) *ok = false;
24 return isolate->factory()->empty_string();
25 }
26
27 const int capture_end_index = RegExpMatchInfo::capture_end_index(capture);
28 const int match_start = match_info->capture(capture_start_index);
29 const int match_end = match_info->capture(capture_end_index);
30 if (match_start == -1 || match_end == -1) {
31 if (ok != nullptr) *ok = false;
32 return isolate->factory()->empty_string();
33 }
34
35 if (ok != nullptr) *ok = true;
36 Handle<String> last_subject(match_info->last_subject(), isolate);
37 return isolate->factory()->NewSubString(last_subject, match_start, match_end);
38}
39
40// static
42 int capture) {
43 // Sentinel used as failure indicator in other functions.
44 if (capture == -1) return false;
45
46 const int capture_start_index = RegExpMatchInfo::capture_start_index(capture);
47 if (capture_start_index >= match_info->number_of_capture_registers()) {
48 return false;
49 }
50
51 const int capture_end_index = RegExpMatchInfo::capture_end_index(capture);
52 const int match_start = match_info->capture(capture_start_index);
53 const int match_end = match_info->capture(capture_end_index);
54 return match_start != -1 && match_end != -1;
55}
56
57namespace {
58
59V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Tagged<JSReceiver> recv) {
60 return recv->map() == isolate->regexp_function()->initial_map();
61}
62
63} // namespace
64
66 Isolate* isolate, DirectHandle<JSReceiver> recv, uint64_t value) {
67 DirectHandle<Object> value_as_object =
68 isolate->factory()->NewNumberFromInt64(value);
69 if (HasInitialRegExpMap(isolate, *recv)) {
70 Cast<JSRegExp>(*recv)->set_last_index(*value_as_object,
72 return recv;
73 } else {
75 isolate, recv, isolate->factory()->lastIndex_string(), value_as_object,
77 }
78}
79
81 Isolate* isolate, DirectHandle<JSReceiver> recv) {
82 if (HasInitialRegExpMap(isolate, *recv)) {
83 return direct_handle(Cast<JSRegExp>(*recv)->last_index(), isolate);
84 } else {
85 return Object::GetProperty(isolate, recv,
86 isolate->factory()->lastIndex_string());
87 }
88}
89
90// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
91// Also takes an optional exec method in case our caller
92// has already fetched exec.
94 Isolate* isolate, DirectHandle<JSReceiver> regexp,
96 if (IsUndefined(*exec, isolate)) {
98 isolate, exec,
99 Object::GetProperty(isolate, regexp,
100 isolate->factory()->exec_string()));
101 }
102
103 if (IsCallable(*exec)) {
104 constexpr int argc = 1;
105 std::array<DirectHandle<Object>, argc> args = {string};
106
109 isolate, result,
111 Execution::Call(isolate, exec, regexp, base::VectorOf(args))));
112
113 if (!IsJSReceiver(*result) && !IsNull(*result, isolate)) {
114 THROW_NEW_ERROR(isolate,
115 NewTypeError(MessageTemplate::kInvalidRegExpExecResult));
116 }
117 return result;
118 }
119
120 if (!IsJSRegExp(*regexp)) {
121 THROW_NEW_ERROR(isolate,
122 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
123 isolate->factory()->NewStringFromAsciiChecked(
124 "RegExp.prototype.exec"),
125 regexp));
126 }
127
128 {
129 DirectHandle<JSFunction> regexp_exec = isolate->regexp_exec_function();
130
131 constexpr int argc = 1;
132 std::array<DirectHandle<Object>, argc> args = {string};
133
134 return Cast<JSAny>(
135 Execution::Call(isolate, regexp_exec, regexp, base::VectorOf(args)));
136 }
137}
138
141#ifdef V8_ENABLE_FORCE_SLOW_PATH
142 if (isolate->force_slow_path()) return false;
143#endif
144
145 if (!IsJSReceiver(*obj)) return false;
146
148
149 if (!HasInitialRegExpMap(isolate, recv)) return false;
150
151 // Check the receiver's prototype's map.
152 Tagged<Object> proto = recv->map()->prototype();
153 if (!IsJSReceiver(proto)) return false;
154
155 DirectHandle<Map> initial_proto_initial_map = isolate->regexp_prototype_map();
156 Tagged<Map> proto_map = Cast<JSReceiver>(proto)->map();
157 if (proto_map != *initial_proto_initial_map) {
158 return false;
159 }
160
161 // Check that the "exec" method is unmodified.
162 // Check that the index refers to "exec" method (this has to be consistent
163 // with the init order in the bootstrapper).
165 DCHECK_EQ(*(isolate->factory()->exec_string()),
166 proto_map->instance_descriptors(isolate)->GetKey(kExecIndex));
167 if (proto_map->instance_descriptors(isolate)
168 ->GetDetails(kExecIndex)
169 .constness() != PropertyConstness::kConst) {
170 return false;
171 }
172
173 // Note: Unlike the more involved check in CSA (see BranchIfFastRegExp), this
174 // does not go on to check the actual value of the exec property. This would
175 // not be valid since this method is called from places that access the flags
176 // property. Similar spots in CSA would use BranchIfFastRegExp_Strict in this
177 // case.
178
179 if (!Protectors::IsRegExpSpeciesLookupChainIntact(isolate)) return false;
180
181 // The smi check is required to omit ToLength(lastIndex) calls with possible
182 // user-code execution on the fast path.
183 Tagged<Object> last_index = Cast<JSRegExp>(recv)->last_index();
184 return IsSmi(last_index) && Smi::ToInt(last_index) >= 0;
185}
186
187uint64_t RegExpUtils::AdvanceStringIndex(Tagged<String> string, uint64_t index,
188 bool unicode) {
189 DCHECK_LE(static_cast<double>(index), kMaxSafeInteger);
190 const uint64_t string_length = static_cast<uint64_t>(string->length());
191 if (unicode && index < string_length) {
192 const uint16_t first = string->Get(static_cast<uint32_t>(index));
193 if (first >= 0xD800 && first <= 0xDBFF && index + 1 < string_length) {
194 DCHECK_LT(index, std::numeric_limits<uint64_t>::max());
195 const uint16_t second = string->Get(static_cast<uint32_t>(index + 1));
196 if (second >= 0xDC00 && second <= 0xDFFF) {
197 return index + 2;
198 }
199 }
200 }
201
202 return index + 1;
203}
204
206 Isolate* isolate, DirectHandle<JSReceiver> regexp,
207 DirectHandle<String> string, bool unicode) {
208 DirectHandle<Object> last_index_obj;
210 isolate, last_index_obj,
211 Object::GetProperty(isolate, regexp,
212 isolate->factory()->lastIndex_string()));
213
214 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
215 Object::ToLength(isolate, last_index_obj));
216 const uint64_t last_index = PositiveNumberToUint64(*last_index_obj);
217 const uint64_t new_last_index =
218 AdvanceStringIndex(*string, last_index, unicode);
219
220 return SetLastIndex(isolate, regexp, new_last_index);
221}
222
223} // namespace internal
224} // namespace v8
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
static constexpr int kExecFunctionDescriptorIndex
Definition js-regexp.h:122
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > ToLength(Isolate *isolate, DirectHandle< Object > input)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > SetProperty(LookupIterator *it, DirectHandle< Object > value, StoreOrigin store_origin, Maybe< ShouldThrow > should_throw=Nothing< ShouldThrow >())
Definition objects.cc:2439
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it, bool is_global_reference=false)
Definition objects.cc:1248
static constexpr int capture_start_index(int capture_index)
static constexpr int capture_end_index(int capture_index)
static Handle< String > GenericCaptureGetter(Isolate *isolate, DirectHandle< RegExpMatchInfo > match_info, int capture, bool *ok=nullptr)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetLastIndex(Isolate *isolate, DirectHandle< JSReceiver > recv)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetAdvancedStringIndex(Isolate *isolate, DirectHandle< JSReceiver > regexp, DirectHandle< String > string, bool unicode)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetLastIndex(Isolate *isolate, DirectHandle< JSReceiver > regexp, uint64_t value)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSAny > RegExpExec(Isolate *isolate, DirectHandle< JSReceiver > regexp, DirectHandle< String > string, DirectHandle< Object > exec)
static uint64_t AdvanceStringIndex(Tagged< String > string, uint64_t index, bool unicode)
static bool IsMatchedCapture(Tagged< RegExpMatchInfo > match_info, int capture)
static bool IsUnmodifiedRegExp(Isolate *isolate, DirectHandle< Object > obj)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
double second
ZoneVector< RpoNumber > & result
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
constexpr double kMaxSafeInteger
Definition globals.h:1985
@ UPDATE_WRITE_BARRIER
Definition objects.h:55
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
uint64_t PositiveNumberToUint64(Tagged< Object > number)
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_INLINE
Definition v8config.h:500