Line data Source code
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 :
5 : #include "src/regexp/regexp-utils.h"
6 :
7 : #include "src/factory.h"
8 : #include "src/isolate.h"
9 : #include "src/objects-inl.h"
10 : #include "src/regexp/jsregexp.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 284752 : Handle<String> RegExpUtils::GenericCaptureGetter(
16 : Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture,
17 : bool* ok) {
18 284752 : const int index = capture * 2;
19 284752 : if (index >= match_info->NumberOfCaptureRegisters()) {
20 2004 : if (ok != nullptr) *ok = false;
21 : return isolate->factory()->empty_string();
22 : }
23 :
24 : const int match_start = match_info->Capture(index);
25 : const int match_end = match_info->Capture(index + 1);
26 282748 : if (match_start == -1 || match_end == -1) {
27 212 : if (ok != nullptr) *ok = false;
28 : return isolate->factory()->empty_string();
29 : }
30 :
31 282536 : if (ok != nullptr) *ok = true;
32 : Handle<String> last_subject(match_info->LastSubject());
33 282536 : return isolate->factory()->NewSubString(last_subject, match_start, match_end);
34 : }
35 :
36 : namespace {
37 :
38 : V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) {
39 6284 : return recv->map() == isolate->regexp_function()->initial_map();
40 : }
41 :
42 : } // namespace
43 :
44 3022 : MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate,
45 : Handle<JSReceiver> recv,
46 : int value) {
47 3022 : if (HasInitialRegExpMap(isolate, recv)) {
48 : JSRegExp::cast(*recv)->set_last_index(Smi::FromInt(value),
49 2872 : SKIP_WRITE_BARRIER);
50 2872 : return recv;
51 : } else {
52 : return Object::SetProperty(recv, isolate->factory()->lastIndex_string(),
53 : handle(Smi::FromInt(value), isolate),
54 150 : LanguageMode::kStrict);
55 : }
56 : }
57 :
58 120 : MaybeHandle<Object> RegExpUtils::GetLastIndex(Isolate* isolate,
59 : Handle<JSReceiver> recv) {
60 120 : if (HasInitialRegExpMap(isolate, recv)) {
61 100 : return handle(JSRegExp::cast(*recv)->last_index(), isolate);
62 : } else {
63 20 : return Object::GetProperty(recv, isolate->factory()->lastIndex_string());
64 : }
65 : }
66 :
67 : // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
68 : // Also takes an optional exec method in case our caller
69 : // has already fetched exec.
70 918 : MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate,
71 : Handle<JSReceiver> regexp,
72 : Handle<String> string,
73 : Handle<Object> exec) {
74 918 : if (exec->IsUndefined(isolate)) {
75 1836 : ASSIGN_RETURN_ON_EXCEPTION(
76 : isolate, exec,
77 : Object::GetProperty(regexp, isolate->factory()->exec_string()), Object);
78 : }
79 :
80 918 : if (exec->IsCallable()) {
81 : const int argc = 1;
82 : ScopedVector<Handle<Object>> argv(argc);
83 888 : argv[0] = string;
84 :
85 : Handle<Object> result;
86 1776 : ASSIGN_RETURN_ON_EXCEPTION(
87 : isolate, result,
88 : Execution::Call(isolate, exec, regexp, argc, argv.start()), Object);
89 :
90 1309 : if (!result->IsJSReceiver() && !result->IsNull(isolate)) {
91 0 : THROW_NEW_ERROR(isolate,
92 : NewTypeError(MessageTemplate::kInvalidRegExpExecResult),
93 : Object);
94 : }
95 878 : return result;
96 : }
97 :
98 30 : if (!regexp->IsJSRegExp()) {
99 0 : THROW_NEW_ERROR(isolate,
100 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
101 : isolate->factory()->NewStringFromAsciiChecked(
102 : "RegExp.prototype.exec"),
103 : regexp),
104 : Object);
105 : }
106 :
107 : {
108 30 : Handle<JSFunction> regexp_exec = isolate->regexp_exec_function();
109 :
110 : const int argc = 1;
111 : ScopedVector<Handle<Object>> argv(argc);
112 30 : argv[0] = string;
113 :
114 30 : return Execution::Call(isolate, regexp_exec, regexp, argc, argv.start());
115 : }
116 : }
117 :
118 40016 : Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) {
119 40016 : if (!object->IsJSReceiver()) return Just(false);
120 :
121 515 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
122 :
123 : Handle<Object> match;
124 1030 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
125 : isolate, match,
126 : JSObject::GetProperty(receiver, isolate->factory()->match_symbol()),
127 : Nothing<bool>());
128 :
129 733 : if (!match->IsUndefined(isolate)) return Just(match->BooleanValue());
130 : return Just(object->IsJSRegExp());
131 : }
132 :
133 6441 : bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
134 : // TODO(ishell): Update this check once map changes for constant field
135 : // tracking are landing.
136 :
137 6441 : if (!obj->IsJSReceiver()) return false;
138 :
139 : JSReceiver* recv = JSReceiver::cast(*obj);
140 :
141 : // Check the receiver's map.
142 6441 : Handle<JSFunction> regexp_function = isolate->regexp_function();
143 6441 : if (recv->map() != regexp_function->initial_map()) return false;
144 :
145 : // Check the receiver's prototype's map.
146 : Object* proto = recv->map()->prototype();
147 6231 : if (!proto->IsJSReceiver()) return false;
148 :
149 6231 : Handle<Map> initial_proto_initial_map = isolate->regexp_prototype_map();
150 6231 : if (JSReceiver::cast(proto)->map() != *initial_proto_initial_map) {
151 : return false;
152 : }
153 :
154 : // The smi check is required to omit ToLength(lastIndex) calls with possible
155 : // user-code execution on the fast path.
156 : Object* last_index = JSRegExp::cast(recv)->last_index();
157 12269 : return last_index->IsSmi() && Smi::ToInt(last_index) >= 0;
158 : }
159 :
160 170 : int RegExpUtils::AdvanceStringIndex(Isolate* isolate, Handle<String> string,
161 : int index, bool unicode) {
162 170 : if (unicode && index < string->length()) {
163 : const uint16_t first = string->Get(index);
164 0 : if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) {
165 0 : const uint16_t second = string->Get(index + 1);
166 0 : if (second >= 0xDC00 && second <= 0xDFFF) {
167 0 : return index + 2;
168 : }
169 : }
170 : }
171 :
172 170 : return index + 1;
173 : }
174 :
175 0 : MaybeHandle<Object> RegExpUtils::SetAdvancedStringIndex(
176 : Isolate* isolate, Handle<JSReceiver> regexp, Handle<String> string,
177 : bool unicode) {
178 : Handle<Object> last_index_obj;
179 0 : ASSIGN_RETURN_ON_EXCEPTION(
180 : isolate, last_index_obj,
181 : Object::GetProperty(regexp, isolate->factory()->lastIndex_string()),
182 : Object);
183 :
184 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
185 : Object::ToLength(isolate, last_index_obj), Object);
186 0 : const int last_index = PositiveNumberToUint32(*last_index_obj);
187 : const int new_last_index =
188 0 : AdvanceStringIndex(isolate, string, last_index, unicode);
189 :
190 0 : return SetLastIndex(isolate, regexp, new_last_index);
191 : }
192 :
193 : } // namespace internal
194 : } // namespace v8
|