Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: src/builtins/builtins-regexp.cc

Issue 2394713003: [regexp] Port test, match, and search (Closed)
Patch Set: Rebaseline bytecode expectations Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/contexts.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins-utils.h" 5 #include "src/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/regexp/jsregexp.h" 9 #include "src/regexp/jsregexp.h"
10 #include "src/string-builder.h" 10 #include "src/string-builder.h"
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 static const int field_offset = 209 static const int field_offset =
210 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 210 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
211 var_value.Bind(a->LoadObjectField(regexp, field_offset)); 211 var_value.Bind(a->LoadObjectField(regexp, field_offset));
212 a->Goto(&out); 212 a->Goto(&out);
213 } 213 }
214 214
215 a->Bind(&if_modified); 215 a->Bind(&if_modified);
216 { 216 {
217 // Load through the GetProperty stub. 217 // Load through the GetProperty stub.
218 Node* const name = 218 Node* const name =
219 a->HeapConstant(a->isolate()->factory()->last_index_string()); 219 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
220 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 220 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
221 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name)); 221 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name));
222 a->Goto(&out); 222 a->Goto(&out);
223 } 223 }
224 224
225 a->Bind(&out); 225 a->Bind(&out);
226 return var_value.value(); 226 return var_value.value();
227 } 227 }
228 228
229 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, 229 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
(...skipping 12 matching lines...) Expand all
242 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 242 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
243 a->StoreObjectField(regexp, field_offset, value); 243 a->StoreObjectField(regexp, field_offset, value);
244 a->Goto(&out); 244 a->Goto(&out);
245 } 245 }
246 246
247 a->Bind(&if_modified); 247 a->Bind(&if_modified);
248 { 248 {
249 // Store through runtime. 249 // Store through runtime.
250 // TODO(ishell): Use SetPropertyStub here once available. 250 // TODO(ishell): Use SetPropertyStub here once available.
251 Node* const name = 251 Node* const name =
252 a->HeapConstant(a->isolate()->factory()->last_index_string()); 252 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
253 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); 253 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
254 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, 254 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
255 language_mode); 255 language_mode);
256 a->Goto(&out); 256 a->Goto(&out);
257 } 257 }
258 258
259 a->Bind(&out); 259 a->Bind(&out);
260 } 260 }
261 261
262 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, 262 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate,
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 } 969 }
970 970
971 BUILTIN(RegExpRightContextGetter) { 971 BUILTIN(RegExpRightContextGetter) {
972 HandleScope scope(isolate); 972 HandleScope scope(isolate);
973 const int start_index = GetLastMatchCapture(isolate, 1); 973 const int start_index = GetLastMatchCapture(isolate, 1);
974 Handle<String> last_subject = GetLastMatchSubject(isolate); 974 Handle<String> last_subject = GetLastMatchSubject(isolate);
975 const int len = last_subject->length(); 975 const int len = last_subject->length();
976 return *isolate->factory()->NewSubString(last_subject, start_index, len); 976 return *isolate->factory()->NewSubString(last_subject, start_index, len);
977 } 977 }
978 978
979 namespace {
980
981 V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) {
982 return recv->map() == isolate->regexp_function()->initial_map();
983 }
984
985 } // namespace
986
987 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
988 // Also takes an optional exec method in case our caller
989 // has already fetched exec.
990 MaybeHandle<Object> RegExpExec(Isolate* isolate, Handle<JSReceiver> regexp,
991 Handle<String> string, Handle<Object> exec) {
992 if (exec->IsUndefined(isolate)) {
993 ASSIGN_RETURN_ON_EXCEPTION(
994 isolate, exec,
995 Object::GetProperty(
996 regexp, isolate->factory()->NewStringFromAsciiChecked("exec")),
997 Object);
998 }
999
1000 if (exec->IsCallable()) {
1001 const int argc = 1;
1002 ScopedVector<Handle<Object>> argv(argc);
1003 argv[0] = string;
1004
1005 Handle<Object> result;
1006 ASSIGN_RETURN_ON_EXCEPTION(
1007 isolate, result,
1008 Execution::Call(isolate, exec, regexp, argc, argv.start()), Object);
1009
1010 if (!result->IsJSReceiver() && !result->IsNull(isolate)) {
1011 THROW_NEW_ERROR(isolate,
1012 NewTypeError(MessageTemplate::kInvalidRegExpExecResult),
1013 Object);
1014 }
1015 return result;
1016 }
1017
1018 if (!regexp->IsJSRegExp()) {
1019 THROW_NEW_ERROR(isolate,
1020 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1021 isolate->factory()->NewStringFromAsciiChecked(
1022 "RegExp.prototype.exec"),
1023 regexp),
1024 Object);
1025 }
1026
1027 {
1028 Handle<JSFunction> regexp_exec = isolate->regexp_exec_function();
1029
1030 const int argc = 1;
1031 ScopedVector<Handle<Object>> argv(argc);
1032 argv[0] = string;
1033
1034 return Execution::Call(isolate, exec, regexp_exec, argc, argv.start());
1035 }
1036 }
1037
1038 // ES#sec-regexp.prototype.test
1039 // RegExp.prototype.test ( S )
1040 BUILTIN(RegExpPrototypeTest) {
1041 HandleScope scope(isolate);
1042 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.test");
1043
1044 Handle<Object> string_obj = args.atOrUndefined(isolate, 1);
1045
1046 Handle<String> string;
1047 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
1048 Object::ToString(isolate, string_obj));
1049
1050 Handle<Object> result;
1051 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1052 isolate, result,
1053 RegExpExec(isolate, recv, string, isolate->factory()->undefined_value()));
1054
1055 return isolate->heap()->ToBoolean(!result->IsNull(isolate));
1056 }
1057
1058 namespace {
1059
1060 // ES#sec-advancestringindex
1061 // AdvanceStringIndex ( S, index, unicode )
1062 int AdvanceStringIndex(Isolate* isolate, Handle<String> string, int index,
1063 bool unicode) {
1064 int increment = 1;
1065
1066 if (unicode && index < string->length()) {
1067 const uint16_t first = string->Get(index);
1068 if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) {
1069 const uint16_t second = string->Get(index + 1);
1070 if (second >= 0xDC00 && second <= 0xDFFF) {
1071 increment = 2;
1072 }
1073 }
1074 }
1075
1076 return increment;
1077 }
1078
1079 MaybeHandle<Object> SetLastIndex(Isolate* isolate, Handle<JSReceiver> recv,
1080 int value) {
1081 if (HasInitialRegExpMap(isolate, recv)) {
1082 JSRegExp::cast(*recv)->SetLastIndex(value);
1083 return recv;
1084 } else {
1085 return Object::SetProperty(recv, isolate->factory()->lastIndex_string(),
1086 handle(Smi::FromInt(value), isolate), STRICT);
1087 }
1088 }
1089
1090 MaybeHandle<Object> GetLastIndex(Isolate* isolate, Handle<JSReceiver> recv) {
1091 if (HasInitialRegExpMap(isolate, recv)) {
1092 return handle(JSRegExp::cast(*recv)->LastIndex(), isolate);
1093 } else {
1094 return Object::GetProperty(recv, isolate->factory()->lastIndex_string());
1095 }
1096 }
1097
1098 MaybeHandle<Object> SetAdvancedStringIndex(Isolate* isolate,
1099 Handle<JSReceiver> regexp,
1100 Handle<String> string,
1101 bool unicode) {
1102 Handle<Object> last_index_obj;
1103 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
1104 GetLastIndex(isolate, regexp), Object);
1105
1106 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
1107 Object::ToLength(isolate, last_index_obj), Object);
1108
1109 const int last_index = Handle<Smi>::cast(last_index_obj)->value();
1110 const int new_last_index =
1111 last_index + AdvanceStringIndex(isolate, string, last_index, unicode);
1112
1113 return SetLastIndex(isolate, regexp, new_last_index);
1114 }
1115
1116 } // namespace
1117
1118 // ES#sec-regexp.prototype-@@match
1119 // RegExp.prototype [ @@match ] ( string )
1120 BUILTIN(RegExpPrototypeMatch) {
1121 HandleScope scope(isolate);
1122 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@match");
1123
1124 Handle<Object> string_obj = args.atOrUndefined(isolate, 1);
1125
1126 Handle<String> string;
1127 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
1128 Object::ToString(isolate, string_obj));
1129
1130 Handle<Object> global_obj;
1131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1132 isolate, global_obj,
1133 JSReceiver::GetProperty(recv, isolate->factory()->global_string()));
1134 const bool global = global_obj->BooleanValue();
1135
1136 if (!global) {
1137 RETURN_RESULT_OR_FAILURE(isolate,
1138 RegExpExec(isolate, recv, string,
1139 isolate->factory()->undefined_value()));
1140 }
1141
1142 Handle<Object> unicode_obj;
1143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1144 isolate, unicode_obj,
1145 JSReceiver::GetProperty(recv, isolate->factory()->unicode_string()));
1146 const bool unicode = unicode_obj->BooleanValue();
1147
1148 RETURN_FAILURE_ON_EXCEPTION(isolate, SetLastIndex(isolate, recv, 0));
1149
1150 static const int kInitialArraySize = 8;
1151 Handle<FixedArray> elems =
1152 isolate->factory()->NewFixedArrayWithHoles(kInitialArraySize);
1153
1154 int n = 0;
1155 for (;; n++) {
1156 Handle<Object> result;
1157 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1158 isolate, result, RegExpExec(isolate, recv, string,
1159 isolate->factory()->undefined_value()));
1160
1161 if (result->IsNull(isolate)) {
1162 if (n == 0) return isolate->heap()->null_value();
1163 break;
1164 }
1165
1166 Handle<Object> match_obj;
1167 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match_obj,
1168 Object::GetElement(isolate, result, 0));
1169
1170 Handle<String> match;
1171 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match,
1172 Object::ToString(isolate, match_obj));
1173
1174 elems = FixedArray::SetAndGrow(elems, n, match);
1175
1176 if (match->length() == 0) {
1177 RETURN_FAILURE_ON_EXCEPTION(
1178 isolate, SetAdvancedStringIndex(isolate, recv, string, unicode));
1179 }
1180 }
1181
1182 elems->Shrink(n);
1183 return *isolate->factory()->NewJSArrayWithElements(elems);
1184 }
1185
1186 // ES#sec-regexp.prototype-@@search
1187 // RegExp.prototype [ @@search ] ( string )
1188 BUILTIN(RegExpPrototypeSearch) {
1189 HandleScope scope(isolate);
1190 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search");
1191
1192 Handle<Object> string_obj = args.atOrUndefined(isolate, 1);
1193
1194 Handle<String> string;
1195 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
1196 Object::ToString(isolate, string_obj));
1197
1198 Handle<Object> previous_last_index_obj;
1199 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj,
1200 GetLastIndex(isolate, recv));
1201
1202 if (!previous_last_index_obj->IsSmi() ||
1203 Smi::cast(*previous_last_index_obj)->value() != 0) {
1204 RETURN_FAILURE_ON_EXCEPTION(isolate, SetLastIndex(isolate, recv, 0));
1205 }
1206
1207 Handle<Object> result;
1208 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1209 isolate, result,
1210 RegExpExec(isolate, recv, string, isolate->factory()->undefined_value()));
1211
1212 Handle<Object> current_last_index_obj;
1213 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj,
1214 GetLastIndex(isolate, recv));
1215
1216 Maybe<bool> is_last_index_unchanged =
1217 Object::Equals(current_last_index_obj, previous_last_index_obj);
1218 if (is_last_index_unchanged.IsNothing()) return isolate->pending_exception();
1219 if (!is_last_index_unchanged.FromJust()) {
1220 if (previous_last_index_obj->IsSmi()) {
1221 RETURN_FAILURE_ON_EXCEPTION(
1222 isolate, SetLastIndex(isolate, recv,
1223 Smi::cast(*previous_last_index_obj)->value()));
1224 } else {
1225 RETURN_FAILURE_ON_EXCEPTION(
1226 isolate,
1227 Object::SetProperty(recv, isolate->factory()->lastIndex_string(),
1228 previous_last_index_obj, STRICT));
1229 }
1230 }
1231
1232 if (result->IsNull(isolate)) return Smi::FromInt(-1);
1233
1234 RETURN_RESULT_OR_FAILURE(
1235 isolate, Object::GetProperty(result, isolate->factory()->index_string()));
1236 }
1237
979 } // namespace internal 1238 } // namespace internal
980 } // namespace v8 1239 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/contexts.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698