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

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

Issue 2630233003: [regexp] Create property on result for each named capture (Closed)
Patch Set: Remove unused CaptureNameMapOffset Created 3 years, 11 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 | « no previous file | src/regexp/regexp-parser.cc » ('j') | src/regexp/regexp-parser.cc » ('J')
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-constructor.h" 5 #include "src/builtins/builtins-constructor.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 #include "src/builtins/builtins.h" 7 #include "src/builtins/builtins.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h" 9 #include "src/code-stub-assembler.h"
10 #include "src/regexp/jsregexp.h" 10 #include "src/regexp/jsregexp.h"
(...skipping 15 matching lines...) Expand all
26 protected: 26 protected:
27 Node* FastLoadLastIndex(Node* regexp); 27 Node* FastLoadLastIndex(Node* regexp);
28 Node* SlowLoadLastIndex(Node* context, Node* regexp); 28 Node* SlowLoadLastIndex(Node* context, Node* regexp);
29 Node* LoadLastIndex(Node* context, Node* regexp, bool is_fastpath); 29 Node* LoadLastIndex(Node* context, Node* regexp, bool is_fastpath);
30 30
31 void FastStoreLastIndex(Node* regexp, Node* value); 31 void FastStoreLastIndex(Node* regexp, Node* value);
32 void SlowStoreLastIndex(Node* context, Node* regexp, Node* value); 32 void SlowStoreLastIndex(Node* context, Node* regexp, Node* value);
33 void StoreLastIndex(Node* context, Node* regexp, Node* value, 33 void StoreLastIndex(Node* context, Node* regexp, Node* value,
34 bool is_fastpath); 34 bool is_fastpath);
35 35
36 Node* ConstructNewResultFromMatchInfo(Node* context, Node* match_info, 36 Node* ConstructNewResultFromMatchInfo(Node* const context, Node* const regexp,
37 Node* string); 37 Node* const match_info,
38 Node* const string);
38 39
39 Node* RegExpPrototypeExecBodyWithoutResult(Node* const context, 40 Node* RegExpPrototypeExecBodyWithoutResult(Node* const context,
40 Node* const regexp, 41 Node* const regexp,
41 Node* const string, 42 Node* const string,
42 Label* if_didnotmatch, 43 Label* if_didnotmatch,
43 const bool is_fastpath); 44 const bool is_fastpath);
44 Node* RegExpPrototypeExecBody(Node* const context, Node* const regexp, 45 Node* RegExpPrototypeExecBody(Node* const context, Node* const regexp,
45 Node* const string, const bool is_fastpath); 46 Node* const string, const bool is_fastpath);
46 47
47 Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver, 48 Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver,
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 135
135 void RegExpBuiltinsAssembler::StoreLastIndex(Node* context, Node* regexp, 136 void RegExpBuiltinsAssembler::StoreLastIndex(Node* context, Node* regexp,
136 Node* value, bool is_fastpath) { 137 Node* value, bool is_fastpath) {
137 if (is_fastpath) { 138 if (is_fastpath) {
138 FastStoreLastIndex(regexp, value); 139 FastStoreLastIndex(regexp, value);
139 } else { 140 } else {
140 SlowStoreLastIndex(context, regexp, value); 141 SlowStoreLastIndex(context, regexp, value);
141 } 142 }
142 } 143 }
143 144
144 Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(Node* context, 145 Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
145 Node* match_info, 146 Node* const context, Node* const regexp, Node* const match_info,
146 Node* string) { 147 Node* const string) {
147 Label out(this); 148 Label named_captures(this), out(this);
148 149
149 Node* const num_indices = SmiUntag(LoadFixedArrayElement( 150 Node* const num_indices = SmiUntag(LoadFixedArrayElement(
150 match_info, RegExpMatchInfo::kNumberOfCapturesIndex)); 151 match_info, RegExpMatchInfo::kNumberOfCapturesIndex));
151 Node* const num_results = SmiTag(WordShr(num_indices, 1)); 152 Node* const num_results = SmiTag(WordShr(num_indices, 1));
152 Node* const start = 153 Node* const start =
153 LoadFixedArrayElement(match_info, RegExpMatchInfo::kFirstCaptureIndex); 154 LoadFixedArrayElement(match_info, RegExpMatchInfo::kFirstCaptureIndex);
154 Node* const end = LoadFixedArrayElement( 155 Node* const end = LoadFixedArrayElement(
155 match_info, RegExpMatchInfo::kFirstCaptureIndex + 1); 156 match_info, RegExpMatchInfo::kFirstCaptureIndex + 1);
156 157
157 // Calculate the substring of the first match before creating the result array 158 // Calculate the substring of the first match before creating the result array
158 // to avoid an unnecessary write barrier storing the first result. 159 // to avoid an unnecessary write barrier storing the first result.
159 Node* const first = SubString(context, string, start, end); 160 Node* const first = SubString(context, string, start, end);
160 161
161 Node* const result = 162 Node* const result =
162 AllocateRegExpResult(context, num_results, start, string); 163 AllocateRegExpResult(context, num_results, start, string);
163 Node* const result_elements = LoadElements(result); 164 Node* const result_elements = LoadElements(result);
164 165
165 StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); 166 StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER);
166 167
167 GotoIf(SmiEqual(num_results, SmiConstant(Smi::FromInt(1))), &out); 168 GotoIf(SmiEqual(num_results, SmiConstant(1)), &named_captures);
168 169
169 // Store all remaining captures. 170 // Store all remaining captures.
170 Node* const limit = IntPtrAdd( 171 Node* const limit = IntPtrAdd(
171 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); 172 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices);
172 173
173 Variable var_from_cursor(this, MachineType::PointerRepresentation()); 174 Variable var_from_cursor(this, MachineType::PointerRepresentation());
174 Variable var_to_cursor(this, MachineType::PointerRepresentation()); 175 Variable var_to_cursor(this, MachineType::PointerRepresentation());
175 176
176 var_from_cursor.Bind(IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); 177 var_from_cursor.Bind(IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2));
177 var_to_cursor.Bind(IntPtrConstant(1)); 178 var_to_cursor.Bind(IntPtrConstant(1));
178 179
179 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; 180 Variable* vars[] = {&var_from_cursor, &var_to_cursor};
180 Label loop(this, 2, vars); 181 Label loop(this, 2, vars);
181 182
182 Goto(&loop); 183 Goto(&loop);
183 Bind(&loop); 184 Bind(&loop);
184 { 185 {
185 Node* const from_cursor = var_from_cursor.value(); 186 Node* const from_cursor = var_from_cursor.value();
186 Node* const to_cursor = var_to_cursor.value(); 187 Node* const to_cursor = var_to_cursor.value();
187 Node* const start = LoadFixedArrayElement(match_info, from_cursor); 188 Node* const start = LoadFixedArrayElement(match_info, from_cursor);
188 189
189 Label next_iter(this); 190 Label next_iter(this);
190 GotoIf(SmiEqual(start, SmiConstant(Smi::FromInt(-1))), &next_iter); 191 GotoIf(SmiEqual(start, SmiConstant(-1)), &next_iter);
191 192
192 Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1)); 193 Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1));
193 Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1); 194 Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1);
194 195
195 Node* const capture = SubString(context, string, start, end); 196 Node* const capture = SubString(context, string, start, end);
196 StoreFixedArrayElement(result_elements, to_cursor, capture); 197 StoreFixedArrayElement(result_elements, to_cursor, capture);
197 Goto(&next_iter); 198 Goto(&next_iter);
198 199
199 Bind(&next_iter); 200 Bind(&next_iter);
200 var_from_cursor.Bind(IntPtrAdd(from_cursor, IntPtrConstant(2))); 201 var_from_cursor.Bind(IntPtrAdd(from_cursor, IntPtrConstant(2)));
201 var_to_cursor.Bind(IntPtrAdd(to_cursor, IntPtrConstant(1))); 202 var_to_cursor.Bind(IntPtrAdd(to_cursor, IntPtrConstant(1)));
202 Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); 203 Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop,
204 &named_captures);
205 }
206
207 Bind(&named_captures);
208 {
209 // Preparations for named capture properties. Exit early if the result is
210 // either not an IRREGEXP or does not have any named captures to minimize
211 // performance impact.
212
213 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE));
214 Node* const data = LoadObjectField(regexp, JSRegExp::kDataOffset);
215 Node* const tag = LoadFixedArrayElement(data, JSRegExp::kTagIndex);
216 GotoUnless(SmiEqual(tag, SmiConstant(JSRegExp::IRREGEXP)), &out);
217
218 // The names fixed array associates names at even indices with a capture
219 // index at odd indices.
220 Node* const names =
221 LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureNameMapIndex);
222 GotoIf(SmiEqual(names, SmiConstant(0)), &out);
Yang 2017/01/18 13:25:36 Why don't we jump to runtime after this? That woul
jgruber 2017/01/19 15:59:12 Once the SetPropertyStub is implemented we'll be a
223
224 // One or more named captures exist, add a property for each one.
225
226 CSA_ASSERT(this, HasInstanceType(names, FIXED_ARRAY_TYPE));
227 Node* const names_length = LoadAndUntagFixedArrayBaseLength(names);
228 CSA_ASSERT(this, IntPtrGreaterThan(names_length, IntPtrConstant(0)));
229
230 Variable var_i(this, MachineType::PointerRepresentation());
231 var_i.Bind(IntPtrConstant(0));
232
233 Variable* vars[] = {&var_i};
234 const int vars_count = sizeof(vars) / sizeof(vars[0]);
235 Label loop(this, vars_count, vars);
236
237 Goto(&loop);
238 Bind(&loop);
239 {
240 Node* const i = var_i.value();
241 Node* const i_plus_1 = IntPtrAdd(i, IntPtrConstant(1));
242 Node* const i_plus_2 = IntPtrAdd(i_plus_1, IntPtrConstant(1));
243
244 Node* const name = LoadFixedArrayElement(names, i);
245 Node* const index = LoadFixedArrayElement(names, i_plus_1);
246 Node* const capture =
247 LoadFixedArrayElement(result_elements, SmiUntag(index));
248
249 Node* const language_mode = SmiConstant(Smi::FromInt(STRICT));
250 CallRuntime(Runtime::kSetProperty, context, result, name, capture,
251 language_mode);
252
253 var_i.Bind(i_plus_2);
254 Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length), &out,
255 &loop);
256 }
203 } 257 }
204 258
205 Bind(&out); 259 Bind(&out);
206 return result; 260 return result;
207 } 261 }
208 262
209 // ES#sec-regexp.prototype.exec 263 // ES#sec-regexp.prototype.exec
210 // RegExp.prototype.exec ( string ) 264 // RegExp.prototype.exec ( string )
211 // Implements the core of RegExp.prototype.exec but without actually 265 // Implements the core of RegExp.prototype.exec but without actually
212 // constructing the JSRegExpResult. Returns either null (if the RegExp did not 266 // constructing the JSRegExpResult. Returns either null (if the RegExp did not
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 Variable var_result(this, MachineRepresentation::kTagged); 399 Variable var_result(this, MachineRepresentation::kTagged);
346 400
347 Label if_didnotmatch(this), out(this); 401 Label if_didnotmatch(this), out(this);
348 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult( 402 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult(
349 context, regexp, string, &if_didnotmatch, is_fastpath); 403 context, regexp, string, &if_didnotmatch, is_fastpath);
350 404
351 // Successful match. 405 // Successful match.
352 { 406 {
353 Node* const match_indices = indices_or_null; 407 Node* const match_indices = indices_or_null;
354 Node* const result = 408 Node* const result =
355 ConstructNewResultFromMatchInfo(context, match_indices, string); 409 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string);
356 var_result.Bind(result); 410 var_result.Bind(result);
357 Goto(&out); 411 Goto(&out);
358 } 412 }
359 413
360 Bind(&if_didnotmatch); 414 Bind(&if_didnotmatch);
361 { 415 {
362 var_result.Bind(null); 416 var_result.Bind(null);
363 Goto(&out); 417 Goto(&out);
364 } 418 }
365 419
(...skipping 2149 matching lines...) Expand 10 before | Expand all | Expand 10 after
2515 2569
2516 Label if_matched(this), if_didnotmatch(this); 2570 Label if_matched(this), if_didnotmatch(this);
2517 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); 2571 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
2518 2572
2519 Bind(&if_didnotmatch); 2573 Bind(&if_didnotmatch);
2520 Return(null); 2574 Return(null);
2521 2575
2522 Bind(&if_matched); 2576 Bind(&if_matched);
2523 { 2577 {
2524 Node* result = 2578 Node* result =
2525 ConstructNewResultFromMatchInfo(context, match_indices, string); 2579 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string);
2526 Return(result); 2580 Return(result);
2527 } 2581 }
2528 } 2582 }
2529 2583
2530 } // namespace internal 2584 } // namespace internal
2531 } // namespace v8 2585 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/regexp/regexp-parser.cc » ('j') | src/regexp/regexp-parser.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698