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

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

Issue 2438683005: [regexp] Move RegExp.prototype[@@search] to TF (Closed)
Patch Set: Rename to TryTaggedToFloat64 Created 4 years, 1 month 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
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/regexp/regexp-utils.h" 10 #include "src/regexp/regexp-utils.h"
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); 163 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags));
164 164
165 // Return undefined for compatibility with JSC. 165 // Return undefined for compatibility with JSC.
166 // See http://crbug.com/585775 for web compat details. 166 // See http://crbug.com/585775 for web compat details.
167 167
168 return isolate->heap()->undefined_value(); 168 return isolate->heap()->undefined_value();
169 } 169 }
170 170
171 namespace { 171 namespace {
172 172
173 compiler::Node* FastLoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
174 compiler::Node* regexp) {
175 // Load the in-object field.
176 static const int field_offset =
177 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
178 return a->LoadObjectField(regexp, field_offset);
179 }
180
181 compiler::Node* SlowLoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
182 compiler::Node* regexp) {
183 // Load through the GetProperty stub.
184 typedef compiler::Node Node;
185
186 Node* const name =
187 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
188 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
189 return a->CallStub(getproperty_callable, context, regexp, name);
190 }
191
173 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, 192 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
174 compiler::Node* has_initialmap, 193 compiler::Node* has_initialmap,
175 compiler::Node* regexp) { 194 compiler::Node* regexp) {
176 typedef CodeStubAssembler::Variable Variable; 195 typedef CodeStubAssembler::Variable Variable;
177 typedef CodeStubAssembler::Label Label; 196 typedef CodeStubAssembler::Label Label;
178 typedef compiler::Node Node;
179 197
180 Variable var_value(a, MachineRepresentation::kTagged); 198 Variable var_value(a, MachineRepresentation::kTagged);
181 199
182 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred); 200 Label out(a), if_unmodified(a), if_modified(a);
183 a->Branch(has_initialmap, &if_unmodified, &if_modified); 201 a->Branch(has_initialmap, &if_unmodified, &if_modified);
184 202
185 a->Bind(&if_unmodified); 203 a->Bind(&if_unmodified);
186 { 204 {
187 // Load the in-object field. 205 var_value.Bind(FastLoadLastIndex(a, context, regexp));
188 static const int field_offset =
189 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
190 var_value.Bind(a->LoadObjectField(regexp, field_offset));
191 a->Goto(&out); 206 a->Goto(&out);
192 } 207 }
193 208
194 a->Bind(&if_modified); 209 a->Bind(&if_modified);
195 { 210 {
196 // Load through the GetProperty stub. 211 var_value.Bind(SlowLoadLastIndex(a, context, regexp));
197 Node* const name =
198 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
199 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
200 var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name));
201 a->Goto(&out); 212 a->Goto(&out);
202 } 213 }
203 214
204 a->Bind(&out); 215 a->Bind(&out);
205 return var_value.value(); 216 return var_value.value();
206 } 217 }
207 218
208 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified 219 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified
209 // JSRegExp instance. 220 // JSRegExp instance.
210 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, 221 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
211 compiler::Node* regexp, compiler::Node* value) { 222 compiler::Node* regexp, compiler::Node* value) {
212 // Store the in-object field. 223 // Store the in-object field.
213 static const int field_offset = 224 static const int field_offset =
214 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 225 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
215 a->StoreObjectField(regexp, field_offset, value); 226 a->StoreObjectField(regexp, field_offset, value);
216 } 227 }
217 228
229 void SlowStoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
230 compiler::Node* regexp, compiler::Node* value) {
231 // Store through runtime.
232 // TODO(ishell): Use SetPropertyStub here once available.
233 typedef compiler::Node Node;
234
235 Node* const name =
236 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
237 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
238 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
239 language_mode);
240 }
241
218 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, 242 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
219 compiler::Node* has_initialmap, compiler::Node* regexp, 243 compiler::Node* has_initialmap, compiler::Node* regexp,
220 compiler::Node* value) { 244 compiler::Node* value) {
221 typedef CodeStubAssembler::Label Label; 245 typedef CodeStubAssembler::Label Label;
222 typedef compiler::Node Node;
223 246
224 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred); 247 Label out(a), if_unmodified(a), if_modified(a);
225 a->Branch(has_initialmap, &if_unmodified, &if_modified); 248 a->Branch(has_initialmap, &if_unmodified, &if_modified);
226 249
227 a->Bind(&if_unmodified); 250 a->Bind(&if_unmodified);
228 { 251 {
229 FastStoreLastIndex(a, context, regexp, value); 252 FastStoreLastIndex(a, context, regexp, value);
230 a->Goto(&out); 253 a->Goto(&out);
231 } 254 }
232 255
233 a->Bind(&if_modified); 256 a->Bind(&if_modified);
234 { 257 {
235 // Store through runtime. 258 SlowStoreLastIndex(a, context, regexp, value);
236 // TODO(ishell): Use SetPropertyStub here once available.
237 Node* const name =
238 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
239 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
240 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
241 language_mode);
242 a->Goto(&out); 259 a->Goto(&out);
243 } 260 }
244 261
245 a->Bind(&out); 262 a->Bind(&out);
246 } 263 }
247 264
248 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, 265 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate,
249 CodeStubAssembler* a, 266 CodeStubAssembler* a,
250 compiler::Node* context, 267 compiler::Node* context,
251 compiler::Node* match_info, 268 compiler::Node* match_info,
(...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after
1137 isolate, recv, string, unicode)); 1154 isolate, recv, string, unicode));
1138 } 1155 }
1139 } 1156 }
1140 1157
1141 elems->Shrink(n); 1158 elems->Shrink(n);
1142 return *isolate->factory()->NewJSArrayWithElements(elems); 1159 return *isolate->factory()->NewJSArrayWithElements(elems);
1143 } 1160 }
1144 1161
1145 // ES#sec-regexp.prototype-@@search 1162 // ES#sec-regexp.prototype-@@search
1146 // RegExp.prototype [ @@search ] ( string ) 1163 // RegExp.prototype [ @@search ] ( string )
1147 BUILTIN(RegExpPrototypeSearch) { 1164 void Builtins::Generate_RegExpPrototypeSearch(CodeStubAssembler* a) {
1148 HandleScope scope(isolate); 1165 typedef CodeStubAssembler::Label Label;
1149 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search"); 1166 typedef compiler::Node Node;
1150 1167
1151 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); 1168 Isolate* const isolate = a->isolate();
1152 1169
1153 Handle<String> string; 1170 Node* const maybe_receiver = a->Parameter(0);
1154 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, 1171 Node* const maybe_string = a->Parameter(1);
1155 Object::ToString(isolate, string_obj)); 1172 Node* const context = a->Parameter(4);
1156 1173
1157 Handle<Object> previous_last_index_obj; 1174 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1158 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj,
1159 RegExpUtils::GetLastIndex(isolate, recv));
1160 1175
1161 if (!previous_last_index_obj->SameValue(Smi::kZero)) { 1176 // Ensure {maybe_receiver} is a JSReceiver.
1162 RETURN_FAILURE_ON_EXCEPTION(isolate, 1177 Node* const map =
1163 RegExpUtils::SetLastIndex(isolate, recv, 0)); 1178 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver,
1164 } 1179 MessageTemplate::kIncompatibleMethodReceiver,
1180 "RegExp.prototype.@@search");
1181 Node* const receiver = maybe_receiver;
1165 1182
1166 Handle<Object> result; 1183 // Convert {maybe_string} to a String.
1167 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1184 Node* const string = a->ToString(context, maybe_string);
1168 isolate, result,
1169 RegExpUtils::RegExpExec(isolate, recv, string,
1170 isolate->factory()->undefined_value()));
1171 1185
1172 Handle<Object> current_last_index_obj; 1186 Label fast_path(a), slow_path(a);
1173 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj, 1187 BranchIfFastPath(a, context, map, &fast_path, &slow_path);
1174 RegExpUtils::GetLastIndex(isolate, recv));
1175 1188
1176 const bool is_last_index_unchanged = 1189 a->Bind(&fast_path);
1177 current_last_index_obj->SameValue(*previous_last_index_obj); 1190 {
1178 if (!is_last_index_unchanged) { 1191 // Grab the initial value of last index.
1179 if (previous_last_index_obj->IsSmi()) { 1192 Node* const previous_last_index = FastLoadLastIndex(a, context, receiver);
Igor Sheludko 2016/11/11 16:13:21 Given that the only difference between fast and sl
jgruber 2016/11/13 13:00:09 That helper function exists and is used elsewhere
Igor Sheludko 2016/11/13 18:27:59 I meant something like this: BranchIfFastPath(..
jgruber 2016/11/15 10:02:29 Done.
1180 RETURN_FAILURE_ON_EXCEPTION( 1193
1181 isolate, 1194 // Ensure last index is 0.
1182 RegExpUtils::SetLastIndex( 1195 {
1183 isolate, recv, Smi::cast(*previous_last_index_obj)->value())); 1196 Label next(a);
1184 } else { 1197 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next);
Igor Sheludko 2016/11/11 16:13:20 According to my understanding of a spec we must al
jgruber 2016/11/13 13:00:09 Changes to @@search are about to be merged into th
Igor Sheludko 2016/11/13 18:27:59 Ah. Sorry, I didn't notice that. But still the id
jgruber 2016/11/15 10:02:29 Done.
Yang 2016/11/15 13:03:43 Yeah. I agree. Always writing zero avoids the comp
1185 RETURN_FAILURE_ON_EXCEPTION( 1198
1186 isolate, 1199 FastStoreLastIndex(a, context, receiver, smi_zero);
1187 Object::SetProperty(recv, isolate->factory()->lastIndex_string(), 1200 a->Goto(&next);
1188 previous_last_index_obj, STRICT)); 1201
1202 a->Bind(&next);
1203 }
1204
1205 // Call exec.
1206 Node* const match_indices = RegExpExec(a, context, receiver, string);
1207
1208 // Reset last index if necessary.
1209 {
1210 Label next(a);
1211
1212 Node* const current_last_index = FastLoadLastIndex(a, context, receiver);
1213
1214 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context),
Igor Sheludko 2016/11/11 16:13:20 Same here.
jgruber 2016/11/13 13:00:09 See above.
1215 &next);
1216
1217 FastStoreLastIndex(a, context, receiver, previous_last_index);
1218 a->Goto(&next);
1219
1220 a->Bind(&next);
1221 }
1222
1223 // Return -1 if no match was found.
1224 {
1225 Label next(a);
1226 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next);
1227 a->Return(a->SmiConstant(Smi::FromInt(-1)));
Igor Sheludko 2016/11/11 16:13:20 SmiConstant(-1)
jgruber 2016/11/13 13:00:09 Nice, is this a recent change? Will fix.
Igor Sheludko 2016/11/13 18:27:59 Yes.
jgruber 2016/11/15 10:02:29 Done.
1228 a->Bind(&next);
1229 }
1230
1231 // Return the index of the match.
1232 {
1233 Label fast_result(a), slow_result(a, Label::kDeferred);
1234
1235 Node* const native_context = a->LoadNativeContext(context);
1236 Node* const initial_regexp_result_map = a->LoadContextElement(
1237 native_context, Context::REGEXP_RESULT_MAP_INDEX);
1238 Node* const match_indices_map = a->LoadMap(match_indices);
1239
1240 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map),
1241 &fast_result, &slow_result);
1242
1243 a->Bind(&fast_result);
1244 {
1245 Node* const index =
1246 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset,
1247 MachineType::AnyTagged());
1248 a->Return(index);
1249 }
1250
1251 a->Bind(&slow_result);
1252 {
1253 Node* const name = a->HeapConstant(isolate->factory()->index_string());
1254 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
1255 Node* const index =
1256 a->CallStub(getproperty_callable, context, match_indices, name);
1257 a->Return(index);
1258 }
1189 } 1259 }
1190 } 1260 }
1191 1261
1192 if (result->IsNull(isolate)) return Smi::FromInt(-1); 1262 a->Bind(&slow_path);
1263 {
1264 // Grab the initial value of last index.
1265 Node* const previous_last_index = SlowLoadLastIndex(a, context, receiver);
1193 1266
1194 RETURN_RESULT_OR_FAILURE( 1267 // Ensure last index is 0.
1195 isolate, Object::GetProperty(result, isolate->factory()->index_string())); 1268 {
1269 Label next(a);
1270 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next);
Igor Sheludko 2016/11/11 16:13:21 According to my understanding of a spec we must al
jgruber 2016/11/13 13:00:09 See above.
1271
1272 SlowStoreLastIndex(a, context, receiver, smi_zero);
1273 a->Goto(&next);
1274
1275 a->Bind(&next);
1276 }
1277
1278 // Call exec.
1279 Node* const match_indices = RegExpExec(a, context, receiver, string);
1280
1281 // Reset last index if necessary.
1282 {
1283 Label next(a);
1284
1285 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver);
1286
1287 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context),
Igor Sheludko 2016/11/11 16:13:21 Same here.
jgruber 2016/11/13 13:00:09 See above.
1288 &next);
1289
1290 SlowStoreLastIndex(a, context, receiver, previous_last_index);
1291 a->Goto(&next);
1292
1293 a->Bind(&next);
1294 }
1295
1296 // Return -1 if no match was found.
1297 {
1298 Label next(a);
1299 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next);
1300 a->Return(a->SmiConstant(Smi::FromInt(-1)));
1301 a->Bind(&next);
1302 }
1303
1304 // Return the index of the match.
Igor Sheludko 2016/11/11 16:13:20 I guess in this case the match_indices could still
jgruber 2016/11/13 13:00:09 Yes, but I decided against complicating the implem
Igor Sheludko 2016/11/13 18:27:59 Maybe if you follow the GenerateXYZBody idea menti
jgruber 2016/11/15 10:02:29 Done.
1305 {
1306 Node* const name = a->HeapConstant(isolate->factory()->index_string());
1307 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
1308 Node* const index =
1309 a->CallStub(getproperty_callable, context, match_indices, name);
1310 a->Return(index);
1311 }
1312 }
1196 } 1313 }
1197 1314
1198 namespace { 1315 namespace {
1199 1316
1200 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, 1317 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate,
1201 Handle<Object> object, 1318 Handle<Object> object,
1202 uint32_t* out) { 1319 uint32_t* out) {
1203 if (object->IsUndefined(isolate)) { 1320 if (object->IsUndefined(isolate)) {
1204 *out = kMaxUInt32; 1321 *out = kMaxUInt32;
1205 return object; 1322 return object;
(...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after
2008 a->Bind(&if_matched); 2125 a->Bind(&if_matched);
2009 { 2126 {
2010 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, 2127 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context,
2011 match_indices, string); 2128 match_indices, string);
2012 a->Return(result); 2129 a->Return(result);
2013 } 2130 }
2014 } 2131 }
2015 2132
2016 } // namespace internal 2133 } // namespace internal
2017 } // namespace v8 2134 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | src/code-stub-assembler.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698