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

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

Issue 2375953002: [regexp] Port RegExp.prototype.exec to TurboFan (Closed)
Patch Set: Handle smi this values 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
OLDNEW
(Empty)
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/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h"
7
8 #include "src/code-factory.h"
9 #include "src/regexp/jsregexp.h"
10
11 namespace v8 {
12 namespace internal {
13
14 namespace {
15
16 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
17 compiler::Node* has_initialmap,
18 compiler::Node* regexp) {
19 typedef CodeStubAssembler::Variable Variable;
20 typedef CodeStubAssembler::Label Label;
21 typedef compiler::Node Node;
22
23 Variable var_value(a, MachineRepresentation::kTagged);
24
25 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred);
26 a->Branch(has_initialmap, &if_unmodified, &if_modified);
27
28 a->Bind(&if_unmodified);
29 {
30 // Load the in-object field.
31 static const int field_offset =
32 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex;
Igor Sheludko 2016/09/29 12:55:29 kLastIndexFieldIndex is an index, but not an offse
jgruber 2016/09/29 14:40:26 Done.
33 var_value.Bind(a->LoadObjectField(regexp, field_offset));
34 a->Goto(&out);
35 }
36
37 a->Bind(&if_modified);
38 {
39 // Load through runtime.
40 Node* const name =
41 a->HeapConstant(a->isolate()->factory()->last_index_string());
42 var_value.Bind(
43 a->CallRuntime(Runtime::kGetProperty, context, regexp, name));
Igor Sheludko 2016/09/29 12:55:28 You can call GetPropertyStub here instead.
jgruber 2016/09/29 14:40:26 Done.
44 a->Goto(&out);
45 }
46
47 a->Bind(&out);
48 return var_value.value();
49 }
50
51 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
52 compiler::Node* has_initialmap, compiler::Node* regexp,
53 compiler::Node* value) {
54 typedef CodeStubAssembler::Label Label;
55 typedef compiler::Node Node;
56
57 Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred);
58 a->Branch(has_initialmap, &if_unmodified, &if_modified);
59
60 a->Bind(&if_unmodified);
61 {
62 static const int field_offset =
63 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex;
Igor Sheludko 2016/09/29 12:55:28 Same here.
jgruber 2016/09/29 14:40:26 Done.
64 a->StoreObjectField(regexp, field_offset, value);
65 a->Goto(&out);
66 }
67
68 a->Bind(&if_modified);
69 {
70 // Store through runtime.
71 Node* const name =
72 a->HeapConstant(a->isolate()->factory()->last_index_string());
73 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
74 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
Igor Sheludko 2016/09/29 12:55:29 // TODO(ishell): Use SetPropertyStub here once ava
jgruber 2016/09/29 14:40:26 Done.
75 language_mode);
76 a->Goto(&out);
77 }
78
79 a->Bind(&out);
80 }
81
82 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate,
83 CodeStubAssembler* a,
84 compiler::Node* context,
85 compiler::Node* match_elements,
86 compiler::Node* string) {
87 typedef CodeStubAssembler::Variable Variable;
88 typedef CodeStubAssembler::Label Label;
89 typedef compiler::Node Node;
90
91 Label out(a);
92
93 Callable substring_callable = CodeFactory::SubString(isolate);
Benedikt Meurer 2016/09/29 11:10:08 Nit: inline SubString here.
jgruber 2016/09/29 14:40:26 Done.
94 Callable constructresult_callable =
Benedikt Meurer 2016/09/29 11:10:08 Nit: Follow-up CL, please port construct result to
jgruber 2016/09/29 14:40:27 Acknowledged.
95 CodeFactory::RegExpConstructResult(isolate);
96
97 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement(
Igor Sheludko 2016/09/29 12:55:28 Once you avoid mixing int32/intptr indices, please
jgruber 2016/09/29 14:40:27 Done.
98 match_elements, a->IntPtrConstant(RegExpImpl::kLastCaptureCount)));
99 Node* const num_results = a->SmiTag(a->Word32Shr(num_indices, 1));
Igor Sheludko 2016/09/29 12:55:28 WordShr
jgruber 2016/09/29 14:40:26 Done.
100 Node* const start = a->LoadFixedArrayElement(
101 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture));
102 Node* const end = a->LoadFixedArrayElement(
103 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture + 1));
104
105 // Calculate the substring of the first match before creating the result array
106 // to avoid an unnecessary write barrier storing the first result.
107 Node* const first =
108 a->CallStub(substring_callable, context, string, start, end);
109
110 Node* const result = a->CallStub(constructresult_callable, context,
111 num_results, start, string);
112 Node* const result_elements = a->LoadElements(result);
113
114 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first,
115 SKIP_WRITE_BARRIER);
116
117 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out);
118
119 // Store all remaining captures.
120 Node* const limit =
121 a->IntPtrAdd(a->IntPtrConstant(RegExpImpl::kFirstCapture), num_indices);
122
123 Variable var_from_cursor(a, MachineRepresentation::kWord32);
Igor Sheludko 2016/09/29 12:55:28 MachineType::PointerRepesentation() (which is intp
jgruber 2016/09/29 14:40:26 Done.
124 Variable var_to_cursor(a, MachineRepresentation::kWord32);
Igor Sheludko 2016/09/29 12:55:28 Same here.
jgruber 2016/09/29 14:40:27 Done.
125
126 var_from_cursor.Bind(a->IntPtrConstant(RegExpImpl::kFirstCapture + 2));
127 var_to_cursor.Bind(a->IntPtrConstant(1));
128
129 Variable* vars[] = {&var_from_cursor, &var_to_cursor};
130 Label loop(a, 2, vars);
131
132 a->Goto(&loop);
133 a->Bind(&loop);
134 {
135 Node* from_cursor = var_from_cursor.value();
Igor Sheludko 2016/09/29 12:55:28 const?
jgruber 2016/09/29 14:40:26 Done.
136 Node* const to_cursor = var_to_cursor.value();
137 Node* const start = a->LoadFixedArrayElement(match_elements, from_cursor);
138
139 Label next_iter(a);
140 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter);
141
142 Node* from_cursor_plus1 = a->IntPtrAdd(from_cursor, a->IntPtrConstant(1));
Igor Sheludko 2016/09/29 12:55:28 const?
jgruber 2016/09/29 14:40:26 Done.
143 Node* const end =
144 a->LoadFixedArrayElement(match_elements, from_cursor_plus1);
145
146 Node* const capture =
147 a->CallStub(substring_callable, context, string, start, end);
148 a->StoreFixedArrayElement(result_elements, to_cursor, capture);
149 a->Goto(&next_iter);
150
151 a->Bind(&next_iter);
152 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2)));
153 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1)));
154 a->Branch(a->IntPtrLessThan(var_from_cursor.value(), limit), &loop, &out);
Igor Sheludko 2016/09/29 12:55:28 Since we don't expect negative indices here, I wou
jgruber 2016/09/29 14:40:26 Done.
155 }
156
157 a->Bind(&out);
158 return result;
159 }
160
161 } // namespace
162
163 // ES#sec-regexp.prototype.exec
164 // RegExp.prototype.exec ( string )
165 void Builtins::Generate_RegExpPrototypeExec(CodeStubAssembler* a) {
166 typedef CodeStubAssembler::Variable Variable;
167 typedef CodeStubAssembler::Label Label;
168 typedef compiler::Node Node;
169
170 Isolate* const isolate = a->isolate();
171
172 Node* const receiver = a->Parameter(0);
173 Node* const maybe_string = a->Parameter(1);
174 Node* const context = a->Parameter(4);
175
176 Node* const null = a->NullConstant();
177 Node* const int_zero = a->Int32Constant(0);
178 Node* const smi_zero = a->SmiConstant(Smi::FromInt(0));
179
180 // Ensure {receiver} is a JSRegExp.
181 Node* const regexp_map = a->ThrowIfNotType(context, receiver, JS_REGEXP_TYPE,
182 "RegExp.prototype.exec");
183 Node* const regexp = receiver;
184
185 // Check whether the regexp instance is unmodified.
186 Node* const native_context = a->LoadNativeContext(context);
187 Node* const regexp_fun =
188 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
189 Node* const initial_map =
190 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
191 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map);
192
193 // Convert {maybe_string} to a string.
194 Callable tostring_callable = CodeFactory::ToString(isolate);
195 Node* const string = a->CallStub(tostring_callable, context, maybe_string);
196 Node* const string_length = a->LoadStringLength(string);
197
198 // Check whether the regexp is global or sticky, which determines whether we
199 // update last index later on.
200 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
201 Node* const is_global_or_sticky =
202 a->Word32And(a->SmiUntag(flags),
Igor Sheludko 2016/09/29 12:55:29 You are mixing int32/intptr computations here. I t
jgruber 2016/09/29 14:40:26 Done.
203 a->Int32Constant(JSRegExp::kGlobal | JSRegExp::kSticky));
204 Node* const should_update_last_index =
205 a->Word32NotEqual(is_global_or_sticky, int_zero);
206
207 // Grab and possibly update last index.
208 Label run_exec(a);
209 Variable var_lastindex(a, MachineRepresentation::kTagged);
210 {
211 Label if_doupdate(a), if_dontupdate(a);
212 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
213
214 a->Bind(&if_doupdate);
215 {
216 Node* const regexp_lastindex =
217 LoadLastIndex(a, context, has_initialmap, regexp);
218
219 Callable tolength_callable = CodeFactory::ToLength(isolate);
220 Node* const lastindex =
221 a->CallStub(tolength_callable, context, regexp_lastindex);
222 var_lastindex.Bind(lastindex);
223
224 Label if_isoob(a, Label::kDeferred);
225 a->GotoUnless(a->WordIsSmi(lastindex), &if_isoob);
226 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob);
227 a->Goto(&run_exec);
228
229 a->Bind(&if_isoob);
230 {
231 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero);
232 a->Return(null);
233 }
234 }
235
236 a->Bind(&if_dontupdate);
237 {
238 var_lastindex.Bind(smi_zero);
239 a->Goto(&run_exec);
240 }
241 }
242
243 Node* match_indices;
244 Label successful_match(a);
245 a->Bind(&run_exec);
246 {
247 // Get last match info from the context.
248 Node* const native_context = a->LoadNativeContext(context);
Igor Sheludko 2016/09/29 12:55:28 |native_context| loaded above should be still avai
jgruber 2016/09/29 14:40:27 Done.
249 Node* const last_match_info = a->LoadContextElement(
250 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
251
252 // Call the exec stub.
253 Callable exec_callable = CodeFactory::RegExpExec(isolate);
254 match_indices = a->CallStub(exec_callable, context, regexp, string,
255 var_lastindex.value(), last_match_info);
256
257 // {match_indices} is either null or the RegExpLastMatchInfo array.
258 // Return early if exec failed, possibly updating last index.
259 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match);
260
261 Label return_null(a);
262 a->GotoUnless(should_update_last_index, &return_null);
263
264 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero);
265 a->Goto(&return_null);
266
267 a->Bind(&return_null);
268 a->Return(null);
269 }
270
271 Label construct_result(a);
272 a->Bind(&successful_match);
273 {
274 Node* const match_elements = a->LoadElements(match_indices);
275
276 a->GotoUnless(should_update_last_index, &construct_result);
277
278 // Update the new last index from {match_indices}.
279 Node* const new_lastindex = a->LoadFixedArrayElement(
280 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture + 1));
281
282 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex);
283 a->Goto(&construct_result);
284
285 a->Bind(&construct_result);
286 {
287 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context,
288 match_elements, string);
289 a->Return(result);
290 }
291 }
292 }
293
294 } // namespace internal
295 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698