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