OLD | NEW |
---|---|
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 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1137 isolate, recv, string, unicode)); | 1137 isolate, recv, string, unicode)); |
1138 } | 1138 } |
1139 } | 1139 } |
1140 | 1140 |
1141 elems->Shrink(n); | 1141 elems->Shrink(n); |
1142 return *isolate->factory()->NewJSArrayWithElements(elems); | 1142 return *isolate->factory()->NewJSArrayWithElements(elems); |
1143 } | 1143 } |
1144 | 1144 |
1145 // ES#sec-regexp.prototype-@@search | 1145 // ES#sec-regexp.prototype-@@search |
1146 // RegExp.prototype [ @@search ] ( string ) | 1146 // RegExp.prototype [ @@search ] ( string ) |
1147 BUILTIN(RegExpPrototypeSearch) { | 1147 void Builtins::Generate_RegExpPrototypeSearch(CodeStubAssembler* a) { |
1148 HandleScope scope(isolate); | 1148 typedef CodeStubAssembler::Label Label; |
1149 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search"); | 1149 typedef compiler::Node Node; |
1150 | 1150 |
1151 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | 1151 Isolate* const isolate = a->isolate(); |
1152 | 1152 |
1153 Handle<String> string; | 1153 Node* const maybe_receiver = a->Parameter(0); |
1154 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | 1154 Node* const maybe_string = a->Parameter(1); |
1155 Object::ToString(isolate, string_obj)); | 1155 Node* const context = a->Parameter(4); |
1156 | 1156 |
1157 Handle<Object> previous_last_index_obj; | 1157 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 | 1158 |
1161 if (!previous_last_index_obj->IsSmi() || | 1159 // TODO(jgruber): If we need to optimize this further, we could add an entire |
1162 Smi::cast(*previous_last_index_obj)->value() != 0) { | 1160 // separate fast-path, skipping all follow-up map checks since we can |
1163 RETURN_FAILURE_ON_EXCEPTION(isolate, | 1161 // guarantee they won't change. The downside is more code to maintain. |
1164 RegExpUtils::SetLastIndex(isolate, recv, 0)); | 1162 |
1163 // Ensure {maybe_receiver} is a JSReceiver. | |
1164 Node* const map = | |
1165 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver, | |
1166 MessageTemplate::kIncompatibleMethodReceiver, | |
1167 "RegExp.prototype.@@search"); | |
1168 Node* const receiver = maybe_receiver; | |
1169 | |
1170 // Convert {maybe_string} to a String. | |
1171 Node* const string = a->ToString(context, maybe_string); | |
1172 | |
1173 // Grab the initial value of last index. | |
1174 Node* has_initialmap = IsInitialRegExpMap(a, context, map); | |
1175 Node* const previous_last_index = | |
1176 LoadLastIndex(a, context, has_initialmap, receiver); | |
1177 | |
1178 // Ensure last index is 0. | |
1179 { | |
1180 Label next(a); | |
1181 a->GotoIf(a->WordEqual(previous_last_index, smi_zero), &next); | |
1182 | |
1183 StoreLastIndex(a, context, has_initialmap, receiver, smi_zero); | |
Yang
2016/10/25 07:30:12
The spec actually suggests to always set the last
jgruber
2016/10/25 08:40:57
The spec has changed fairly recently to avoid unne
| |
1184 a->Goto(&next); | |
1185 | |
1186 a->Bind(&next); | |
1165 } | 1187 } |
1166 | 1188 |
1167 Handle<Object> result; | 1189 // Call exec. |
1168 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1190 Node* const match_indices = RegExpExec(a, context, receiver, string); |
1169 isolate, result, | |
1170 RegExpUtils::RegExpExec(isolate, recv, string, | |
1171 isolate->factory()->undefined_value())); | |
1172 | 1191 |
1173 Handle<Object> current_last_index_obj; | 1192 // Reset last index if necessary. |
1174 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj, | 1193 { |
1175 RegExpUtils::GetLastIndex(isolate, recv)); | 1194 Label next(a); |
1176 | 1195 |
1177 Maybe<bool> is_last_index_unchanged = | 1196 // Recheck the map since it might have changed. |
1178 Object::Equals(current_last_index_obj, previous_last_index_obj); | 1197 has_initialmap = IsInitialRegExpMap(a, context, map); |
1179 if (is_last_index_unchanged.IsNothing()) return isolate->pending_exception(); | 1198 |
Yang
2016/10/25 07:30:13
This does not seem correct. To throw an exception
jgruber
2016/10/25 08:40:57
Great catch. Looking at this further, we actually
| |
1180 if (!is_last_index_unchanged.FromJust()) { | 1199 Node* const current_last_index = |
1181 if (previous_last_index_obj->IsSmi()) { | 1200 LoadLastIndex(a, context, has_initialmap, receiver); |
Yang
2016/10/25 07:30:12
Again, the spec suggests to always overwrite the l
jgruber
2016/10/25 08:40:57
The spec has changed recently (see above).
| |
1182 RETURN_FAILURE_ON_EXCEPTION( | 1201 |
1183 isolate, | 1202 a->GotoIf(a->WordEqual(current_last_index, previous_last_index), &next); |
1184 RegExpUtils::SetLastIndex( | 1203 |
1185 isolate, recv, Smi::cast(*previous_last_index_obj)->value())); | 1204 StoreLastIndex(a, context, has_initialmap, receiver, previous_last_index); |
1186 } else { | 1205 a->Goto(&next); |
1187 RETURN_FAILURE_ON_EXCEPTION( | 1206 |
1188 isolate, | 1207 a->Bind(&next); |
1189 Object::SetProperty(recv, isolate->factory()->lastIndex_string(), | 1208 } |
1190 previous_last_index_obj, STRICT)); | 1209 |
1210 // Return -1 if no match was found. | |
1211 { | |
1212 Label next(a); | |
1213 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); | |
1214 a->Return(a->SmiConstant(Smi::FromInt(-1))); | |
1215 a->Bind(&next); | |
1216 } | |
1217 | |
1218 // Return the index of the match. | |
1219 { | |
1220 Label fast_path(a), slow_path(a, Label::kDeferred); | |
1221 | |
1222 Node* const native_context = a->LoadNativeContext(context); | |
1223 Node* const initial_regexp_result_map = | |
1224 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | |
1225 Node* const match_indices_map = a->LoadMap(match_indices); | |
1226 | |
1227 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), | |
1228 &fast_path, &slow_path); | |
1229 | |
1230 a->Bind(&fast_path); | |
1231 { | |
1232 Node* const index = | |
1233 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset, | |
1234 MachineType::AnyTagged()); | |
1235 a->Return(index); | |
1236 } | |
1237 | |
1238 a->Bind(&slow_path); | |
1239 { | |
1240 Node* const name = a->HeapConstant(isolate->factory()->index_string()); | |
1241 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | |
1242 Node* const index = | |
1243 a->CallStub(getproperty_callable, context, match_indices, name); | |
1244 a->Return(index); | |
1191 } | 1245 } |
1192 } | 1246 } |
1193 | |
1194 if (result->IsNull(isolate)) return Smi::FromInt(-1); | |
1195 | |
1196 RETURN_RESULT_OR_FAILURE( | |
1197 isolate, Object::GetProperty(result, isolate->factory()->index_string())); | |
1198 } | 1247 } |
1199 | 1248 |
1200 namespace { | 1249 namespace { |
1201 | 1250 |
1202 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, | 1251 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, |
1203 Handle<Object> object, | 1252 Handle<Object> object, |
1204 uint32_t* out) { | 1253 uint32_t* out) { |
1205 if (object->IsUndefined(isolate)) { | 1254 if (object->IsUndefined(isolate)) { |
1206 *out = kMaxUInt32; | 1255 *out = kMaxUInt32; |
1207 return object; | 1256 return object; |
(...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2010 a->Bind(&if_matched); | 2059 a->Bind(&if_matched); |
2011 { | 2060 { |
2012 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 2061 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
2013 match_indices, string); | 2062 match_indices, string); |
2014 a->Return(result); | 2063 a->Return(result); |
2015 } | 2064 } |
2016 } | 2065 } |
2017 | 2066 |
2018 } // namespace internal | 2067 } // namespace internal |
2019 } // namespace v8 | 2068 } // namespace v8 |
OLD | NEW |