V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
regexp-utils.cc
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/heap/factory.h"
8 #include "src/isolate.h"
9 #include "src/objects-inl.h"
10 #include "src/objects/js-regexp-inl.h"
11 #include "src/regexp/jsregexp.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 Handle<String> RegExpUtils::GenericCaptureGetter(
17  Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture,
18  bool* ok) {
19  const int index = capture * 2;
20  if (index >= match_info->NumberOfCaptureRegisters()) {
21  if (ok != nullptr) *ok = false;
22  return isolate->factory()->empty_string();
23  }
24 
25  const int match_start = match_info->Capture(index);
26  const int match_end = match_info->Capture(index + 1);
27  if (match_start == -1 || match_end == -1) {
28  if (ok != nullptr) *ok = false;
29  return isolate->factory()->empty_string();
30  }
31 
32  if (ok != nullptr) *ok = true;
33  Handle<String> last_subject(match_info->LastSubject(), isolate);
34  return isolate->factory()->NewSubString(last_subject, match_start, match_end);
35 }
36 
37 namespace {
38 
39 V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) {
40  return recv->map() == isolate->regexp_function()->initial_map();
41 }
42 
43 } // namespace
44 
45 MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate,
46  Handle<JSReceiver> recv,
47  uint64_t value) {
48  Handle<Object> value_as_object =
49  isolate->factory()->NewNumberFromInt64(value);
50  if (HasInitialRegExpMap(isolate, recv)) {
51  JSRegExp::cast(*recv)->set_last_index(*value_as_object, SKIP_WRITE_BARRIER);
52  return recv;
53  } else {
54  return Object::SetProperty(isolate, recv,
55  isolate->factory()->lastIndex_string(),
56  value_as_object, LanguageMode::kStrict);
57  }
58 }
59 
60 MaybeHandle<Object> RegExpUtils::GetLastIndex(Isolate* isolate,
61  Handle<JSReceiver> recv) {
62  if (HasInitialRegExpMap(isolate, recv)) {
63  return handle(JSRegExp::cast(*recv)->last_index(), isolate);
64  } else {
65  return Object::GetProperty(isolate, recv,
66  isolate->factory()->lastIndex_string());
67  }
68 }
69 
70 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
71 // Also takes an optional exec method in case our caller
72 // has already fetched exec.
73 MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate,
74  Handle<JSReceiver> regexp,
75  Handle<String> string,
76  Handle<Object> exec) {
77  if (exec->IsUndefined(isolate)) {
78  ASSIGN_RETURN_ON_EXCEPTION(
79  isolate, exec,
80  Object::GetProperty(isolate, regexp, isolate->factory()->exec_string()),
81  Object);
82  }
83 
84  if (exec->IsCallable()) {
85  const int argc = 1;
86  ScopedVector<Handle<Object>> argv(argc);
87  argv[0] = string;
88 
89  Handle<Object> result;
90  ASSIGN_RETURN_ON_EXCEPTION(
91  isolate, result,
92  Execution::Call(isolate, exec, regexp, argc, argv.start()), Object);
93 
94  if (!result->IsJSReceiver() && !result->IsNull(isolate)) {
95  THROW_NEW_ERROR(isolate,
96  NewTypeError(MessageTemplate::kInvalidRegExpExecResult),
97  Object);
98  }
99  return result;
100  }
101 
102  if (!regexp->IsJSRegExp()) {
103  THROW_NEW_ERROR(isolate,
104  NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
105  isolate->factory()->NewStringFromAsciiChecked(
106  "RegExp.prototype.exec"),
107  regexp),
108  Object);
109  }
110 
111  {
112  Handle<JSFunction> regexp_exec = isolate->regexp_exec_function();
113 
114  const int argc = 1;
115  ScopedVector<Handle<Object>> argv(argc);
116  argv[0] = string;
117 
118  return Execution::Call(isolate, regexp_exec, regexp, argc, argv.start());
119  }
120 }
121 
122 Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) {
123  if (!object->IsJSReceiver()) return Just(false);
124 
125  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
126 
127  Handle<Object> match;
128  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
129  isolate, match,
130  JSObject::GetProperty(isolate, receiver,
131  isolate->factory()->match_symbol()),
132  Nothing<bool>());
133 
134  if (!match->IsUndefined(isolate)) return Just(match->BooleanValue(isolate));
135  return Just(object->IsJSRegExp());
136 }
137 
138 bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
139 #ifdef V8_ENABLE_FORCE_SLOW_PATH
140  if (isolate->force_slow_path()) return false;
141 #endif
142 
143  if (!obj->IsJSReceiver()) return false;
144 
145  JSReceiver* recv = JSReceiver::cast(*obj);
146 
147  // Check the receiver's map.
148  Handle<JSFunction> regexp_function = isolate->regexp_function();
149  if (recv->map() != regexp_function->initial_map()) return false;
150 
151  // Check the receiver's prototype's map.
152  Object* proto = recv->map()->prototype();
153  if (!proto->IsJSReceiver()) return false;
154 
155  Handle<Map> initial_proto_initial_map = isolate->regexp_prototype_map();
156  Map proto_map = JSReceiver::cast(proto)->map();
157  if (proto_map != *initial_proto_initial_map) {
158  return false;
159  }
160 
161  // Check that the "exec" method is unmodified.
162  if (FLAG_track_constant_fields) {
163  // Check that the index refers to "exec" method (this has to be consistent
164  // with the init order in the bootstrapper).
165  DCHECK_EQ(*(isolate->factory()->exec_string()),
166  proto_map->instance_descriptors()->GetKey(
167  JSRegExp::kExecFunctionDescriptorIndex));
168  if (proto_map->instance_descriptors()
169  ->GetDetails(JSRegExp::kExecFunctionDescriptorIndex)
170  .constness() != PropertyConstness::kConst) {
171  return false;
172  }
173  }
174 
175  if (!isolate->IsRegExpSpeciesLookupChainIntact()) return false;
176 
177  // The smi check is required to omit ToLength(lastIndex) calls with possible
178  // user-code execution on the fast path.
179  Object* last_index = JSRegExp::cast(recv)->last_index();
180  return last_index->IsSmi() && Smi::ToInt(last_index) >= 0;
181 }
182 
183 uint64_t RegExpUtils::AdvanceStringIndex(Handle<String> string, uint64_t index,
184  bool unicode) {
185  DCHECK_LE(static_cast<double>(index), kMaxSafeInteger);
186  const uint64_t string_length = static_cast<uint64_t>(string->length());
187  if (unicode && index < string_length) {
188  const uint16_t first = string->Get(static_cast<uint32_t>(index));
189  if (first >= 0xD800 && first <= 0xDBFF && index + 1 < string_length) {
190  DCHECK_LT(index, std::numeric_limits<uint64_t>::max());
191  const uint16_t second = string->Get(static_cast<uint32_t>(index + 1));
192  if (second >= 0xDC00 && second <= 0xDFFF) {
193  return index + 2;
194  }
195  }
196  }
197 
198  return index + 1;
199 }
200 
201 MaybeHandle<Object> RegExpUtils::SetAdvancedStringIndex(
202  Isolate* isolate, Handle<JSReceiver> regexp, Handle<String> string,
203  bool unicode) {
204  Handle<Object> last_index_obj;
205  ASSIGN_RETURN_ON_EXCEPTION(
206  isolate, last_index_obj,
207  Object::GetProperty(isolate, regexp,
208  isolate->factory()->lastIndex_string()),
209  Object);
210 
211  ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
212  Object::ToLength(isolate, last_index_obj), Object);
213  const uint64_t last_index = PositiveNumberToUint64(*last_index_obj);
214  const uint64_t new_last_index =
215  AdvanceStringIndex(string, last_index, unicode);
216 
217  return SetLastIndex(isolate, regexp, new_last_index);
218 }
219 
220 } // namespace internal
221 } // namespace v8
Definition: libplatform.h:13