Chromium Code Reviews| 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-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 Loading... | |
| 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 Loading... | |
| 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); | |
|
jgruber
2017/01/17 09:26:51
This unconditionally adds two loads and two branch
Yang
2017/01/18 13:25:36
I think we can already make this a bit simpler: we
jgruber
2017/01/19 15:59:12
Very good point, done.
| |
| 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); | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |