| 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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); | 169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); |
| 170 | 170 |
| 171 // Return undefined for compatibility with JSC. | 171 // Return undefined for compatibility with JSC. |
| 172 // See http://crbug.com/585775 for web compat details. | 172 // See http://crbug.com/585775 for web compat details. |
| 173 | 173 |
| 174 return isolate->heap()->undefined_value(); | 174 return isolate->heap()->undefined_value(); |
| 175 } | 175 } |
| 176 | 176 |
| 177 namespace { | 177 namespace { |
| 178 | 178 |
| 179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { | 179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) { |
| 180 // Load the in-object field. | 180 // Load the in-object field. |
| 181 static const int field_offset = | 181 static const int field_offset = |
| 182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 183 return a->LoadObjectField(regexp, field_offset); | 183 return a->LoadObjectField(regexp, field_offset); |
| 184 } | 184 } |
| 185 | 185 |
| 186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { | 186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
| 187 // Load through the GetProperty stub. | 187 // Load through the GetProperty stub. |
| 188 Node* const name = | 188 Node* const name = |
| 189 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 189 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
| 190 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 190 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 191 return a->CallStub(getproperty_callable, context, regexp, name); | 191 return a->CallStub(getproperty_callable, context, regexp, name); |
| 192 } | 192 } |
| 193 | 193 |
| 194 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, | 194 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
| 195 Node* regexp) { | 195 bool is_fastpath) { |
| 196 CVariable var_value(a, MachineRepresentation::kTagged); | 196 return is_fastpath ? FastLoadLastIndex(a, regexp) |
| 197 | 197 : SlowLoadLastIndex(a, context, regexp); |
| 198 CLabel out(a), if_unmodified(a), if_modified(a); | |
| 199 a->Branch(has_initialmap, &if_unmodified, &if_modified); | |
| 200 | |
| 201 a->Bind(&if_unmodified); | |
| 202 { | |
| 203 var_value.Bind(FastLoadLastIndex(a, context, regexp)); | |
| 204 a->Goto(&out); | |
| 205 } | |
| 206 | |
| 207 a->Bind(&if_modified); | |
| 208 { | |
| 209 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); | |
| 210 a->Goto(&out); | |
| 211 } | |
| 212 | |
| 213 a->Bind(&out); | |
| 214 return var_value.value(); | |
| 215 } | 198 } |
| 216 | 199 |
| 217 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified | 200 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified |
| 218 // JSRegExp instance. | 201 // JSRegExp instance. |
| 219 void FastStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, | 202 void FastStoreLastIndex(CodeStubAssembler* a, Node* regexp, Node* value) { |
| 220 Node* value) { | |
| 221 // Store the in-object field. | 203 // Store the in-object field. |
| 222 static const int field_offset = | 204 static const int field_offset = |
| 223 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 205 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 224 a->StoreObjectField(regexp, field_offset, value); | 206 a->StoreObjectField(regexp, field_offset, value); |
| 225 } | 207 } |
| 226 | 208 |
| 227 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, | 209 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
| 228 Node* value) { | 210 Node* value) { |
| 229 // Store through runtime. | 211 // Store through runtime. |
| 230 // TODO(ishell): Use SetPropertyStub here once available. | 212 // TODO(ishell): Use SetPropertyStub here once available. |
| 231 Node* const name = | 213 Node* const name = |
| 232 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 214 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
| 233 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); | 215 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); |
| 234 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, | 216 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, |
| 235 language_mode); | 217 language_mode); |
| 236 } | 218 } |
| 237 | 219 |
| 238 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, | 220 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
| 239 Node* regexp, Node* value) { | 221 Node* value, bool is_fastpath) { |
| 240 CLabel out(a), if_unmodified(a), if_modified(a); | 222 if (is_fastpath) { |
| 241 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 223 FastStoreLastIndex(a, regexp, value); |
| 242 | 224 } else { |
| 243 a->Bind(&if_unmodified); | 225 SlowStoreLastIndex(a, context, regexp, value); |
| 244 { | |
| 245 FastStoreLastIndex(a, context, regexp, value); | |
| 246 a->Goto(&out); | |
| 247 } | 226 } |
| 248 | |
| 249 a->Bind(&if_modified); | |
| 250 { | |
| 251 SlowStoreLastIndex(a, context, regexp, value); | |
| 252 a->Goto(&out); | |
| 253 } | |
| 254 | |
| 255 a->Bind(&out); | |
| 256 } | 227 } |
| 257 | 228 |
| 258 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, | 229 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, |
| 259 Node* context, Node* match_info, | 230 Node* context, Node* match_info, |
| 260 Node* string) { | 231 Node* string) { |
| 261 CLabel out(a); | 232 CLabel out(a); |
| 262 | 233 |
| 263 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 234 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 264 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( | 235 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( |
| 265 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, | 236 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); | 292 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); |
| 322 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); | 293 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); |
| 323 } | 294 } |
| 324 | 295 |
| 325 a->Bind(&out); | 296 a->Bind(&out); |
| 326 return result; | 297 return result; |
| 327 } | 298 } |
| 328 | 299 |
| 329 // ES#sec-regexp.prototype.exec | 300 // ES#sec-regexp.prototype.exec |
| 330 // RegExp.prototype.exec ( string ) | 301 // RegExp.prototype.exec ( string ) |
| 331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, | 302 // Implements the core of RegExp.prototype.exec but without actually |
| 332 Node* maybe_receiver, Node* maybe_string) { | 303 // constructing the JSRegExpResult. Returns either null (if the RegExp did not |
| 304 // match) or a fixed array containing match indices as returned by |
| 305 // RegExpExecStub. |
| 306 Node* RegExpPrototypeExecBodyWithoutResult( |
| 307 CodeStubAssembler* a, Node* const context, Node* const regexp, |
| 308 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) { |
| 333 Isolate* const isolate = a->isolate(); | 309 Isolate* const isolate = a->isolate(); |
| 334 | 310 |
| 335 Node* const null = a->NullConstant(); | 311 Node* const null = a->NullConstant(); |
| 336 Node* const int_zero = a->IntPtrConstant(0); | 312 Node* const int_zero = a->IntPtrConstant(0); |
| 337 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 313 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 338 | 314 |
| 315 if (!is_fastpath) { |
| 316 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
| 317 "RegExp.prototype.exec"); |
| 318 } |
| 319 |
| 320 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string))); |
| 321 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE)); |
| 322 |
| 339 CVariable var_result(a, MachineRepresentation::kTagged); | 323 CVariable var_result(a, MachineRepresentation::kTagged); |
| 340 CLabel out(a); | 324 CLabel out(a); |
| 341 | 325 |
| 342 // Ensure {maybe_receiver} is a JSRegExp. | |
| 343 Node* const regexp_map = a->ThrowIfNotInstanceType( | |
| 344 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | |
| 345 Node* const regexp = maybe_receiver; | |
| 346 | |
| 347 // Check whether the regexp instance is unmodified. | |
| 348 Node* const native_context = a->LoadNativeContext(context); | 326 Node* const native_context = a->LoadNativeContext(context); |
| 349 Node* const regexp_fun = | |
| 350 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | |
| 351 Node* const initial_map = | |
| 352 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | |
| 353 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map); | |
| 354 | |
| 355 // Convert {maybe_string} to a string. | |
| 356 Callable tostring_callable = CodeFactory::ToString(isolate); | |
| 357 Node* const string = a->CallStub(tostring_callable, context, maybe_string); | |
| 358 Node* const string_length = a->LoadStringLength(string); | 327 Node* const string_length = a->LoadStringLength(string); |
| 359 | 328 |
| 360 // Check whether the regexp is global or sticky, which determines whether we | 329 // Check whether the regexp is global or sticky, which determines whether we |
| 361 // update last index later on. | 330 // update last index later on. |
| 362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 331 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 363 Node* const is_global_or_sticky = | 332 Node* const is_global_or_sticky = |
| 364 a->WordAnd(a->SmiUntag(flags), | 333 a->WordAnd(a->SmiUntag(flags), |
| 365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 334 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
| 366 Node* const should_update_last_index = | 335 Node* const should_update_last_index = |
| 367 a->WordNotEqual(is_global_or_sticky, int_zero); | 336 a->WordNotEqual(is_global_or_sticky, int_zero); |
| 368 | 337 |
| 369 // Grab and possibly update last index. | 338 // Grab and possibly update last index. |
| 370 CLabel run_exec(a); | 339 CLabel run_exec(a); |
| 371 CVariable var_lastindex(a, MachineRepresentation::kTagged); | 340 CVariable var_lastindex(a, MachineRepresentation::kTagged); |
| 372 { | 341 { |
| 373 CLabel if_doupdate(a), if_dontupdate(a); | 342 CLabel if_doupdate(a), if_dontupdate(a); |
| 374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); | 343 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); |
| 375 | 344 |
| 376 a->Bind(&if_doupdate); | 345 a->Bind(&if_doupdate); |
| 377 { | 346 { |
| 378 Node* const regexp_lastindex = | 347 Node* const regexp_lastindex = |
| 379 LoadLastIndex(a, context, has_initialmap, regexp); | 348 LoadLastIndex(a, context, regexp, is_fastpath); |
| 349 var_lastindex.Bind(regexp_lastindex); |
| 380 | 350 |
| 381 Callable tolength_callable = CodeFactory::ToLength(isolate); | 351 // Omit ToLength if lastindex is a non-negative smi. |
| 382 Node* const lastindex = | 352 { |
| 383 a->CallStub(tolength_callable, context, regexp_lastindex); | 353 CLabel call_tolength(a, CLabel::kDeferred), next(a); |
| 384 var_lastindex.Bind(lastindex); | 354 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next, |
| 355 &call_tolength); |
| 356 |
| 357 a->Bind(&call_tolength); |
| 358 { |
| 359 Callable tolength_callable = CodeFactory::ToLength(isolate); |
| 360 var_lastindex.Bind( |
| 361 a->CallStub(tolength_callable, context, regexp_lastindex)); |
| 362 a->Goto(&next); |
| 363 } |
| 364 |
| 365 a->Bind(&next); |
| 366 } |
| 367 |
| 368 Node* const lastindex = var_lastindex.value(); |
| 385 | 369 |
| 386 CLabel if_isoob(a, CLabel::kDeferred); | 370 CLabel if_isoob(a, CLabel::kDeferred); |
| 387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); | 371 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); |
| 388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); | 372 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); |
| 389 a->Goto(&run_exec); | 373 a->Goto(&run_exec); |
| 390 | 374 |
| 391 a->Bind(&if_isoob); | 375 a->Bind(&if_isoob); |
| 392 { | 376 { |
| 393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 377 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
| 394 var_result.Bind(null); | 378 var_result.Bind(null); |
| 395 a->Goto(&out); | 379 a->Goto(if_didnotmatch); |
| 396 } | 380 } |
| 397 } | 381 } |
| 398 | 382 |
| 399 a->Bind(&if_dontupdate); | 383 a->Bind(&if_dontupdate); |
| 400 { | 384 { |
| 401 var_lastindex.Bind(smi_zero); | 385 var_lastindex.Bind(smi_zero); |
| 402 a->Goto(&run_exec); | 386 a->Goto(&run_exec); |
| 403 } | 387 } |
| 404 } | 388 } |
| 405 | 389 |
| 406 Node* match_indices; | 390 Node* match_indices; |
| 407 CLabel successful_match(a); | 391 CLabel successful_match(a); |
| 408 a->Bind(&run_exec); | 392 a->Bind(&run_exec); |
| 409 { | 393 { |
| 410 // Get last match info from the context. | 394 // Get last match info from the context. |
| 411 Node* const last_match_info = a->LoadContextElement( | 395 Node* const last_match_info = a->LoadContextElement( |
| 412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 396 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 413 | 397 |
| 414 // Call the exec stub. | 398 // Call the exec stub. |
| 415 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 399 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 416 match_indices = a->CallStub(exec_callable, context, regexp, string, | 400 match_indices = a->CallStub(exec_callable, context, regexp, string, |
| 417 var_lastindex.value(), last_match_info); | 401 var_lastindex.value(), last_match_info); |
| 402 var_result.Bind(match_indices); |
| 418 | 403 |
| 419 // {match_indices} is either null or the RegExpMatchInfo array. | 404 // {match_indices} is either null or the RegExpMatchInfo array. |
| 420 // Return early if exec failed, possibly updating last index. | 405 // Return early if exec failed, possibly updating last index. |
| 421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 406 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
| 422 | 407 |
| 423 CLabel return_null(a); | 408 a->GotoUnless(should_update_last_index, if_didnotmatch); |
| 424 a->GotoUnless(should_update_last_index, &return_null); | |
| 425 | 409 |
| 426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 410 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
| 427 a->Goto(&return_null); | 411 a->Goto(if_didnotmatch); |
| 428 | |
| 429 a->Bind(&return_null); | |
| 430 var_result.Bind(null); | |
| 431 a->Goto(&out); | |
| 432 } | 412 } |
| 433 | 413 |
| 434 CLabel construct_result(a); | |
| 435 a->Bind(&successful_match); | 414 a->Bind(&successful_match); |
| 436 { | 415 { |
| 437 a->GotoUnless(should_update_last_index, &construct_result); | 416 a->GotoUnless(should_update_last_index, &out); |
| 438 | 417 |
| 439 // Update the new last index from {match_indices}. | 418 // Update the new last index from {match_indices}. |
| 440 Node* const new_lastindex = a->LoadFixedArrayElement( | 419 Node* const new_lastindex = a->LoadFixedArrayElement( |
| 441 match_indices, | 420 match_indices, |
| 442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | 421 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
| 443 | 422 |
| 444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 423 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); |
| 445 a->Goto(&construct_result); | 424 a->Goto(&out); |
| 425 } |
| 446 | 426 |
| 447 a->Bind(&construct_result); | 427 a->Bind(&out); |
| 448 { | 428 return var_result.value(); |
| 449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 429 } |
| 450 match_indices, string); | 430 |
| 451 var_result.Bind(result); | 431 // ES#sec-regexp.prototype.exec |
| 452 a->Goto(&out); | 432 // RegExp.prototype.exec ( string ) |
| 453 } | 433 Node* RegExpPrototypeExecBody(CodeStubAssembler* a, Node* const context, |
| 434 Node* const regexp, Node* const string, |
| 435 const bool is_fastpath) { |
| 436 Isolate* const isolate = a->isolate(); |
| 437 Node* const null = a->NullConstant(); |
| 438 |
| 439 CVariable var_result(a, MachineRepresentation::kTagged); |
| 440 |
| 441 CLabel if_didnotmatch(a), out(a); |
| 442 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult( |
| 443 a, context, regexp, string, &if_didnotmatch, is_fastpath); |
| 444 |
| 445 // Successful match. |
| 446 { |
| 447 Node* const match_indices = indices_or_null; |
| 448 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context, |
| 449 match_indices, string); |
| 450 var_result.Bind(result); |
| 451 a->Goto(&out); |
| 452 } |
| 453 |
| 454 a->Bind(&if_didnotmatch); |
| 455 { |
| 456 var_result.Bind(null); |
| 457 a->Goto(&out); |
| 454 } | 458 } |
| 455 | 459 |
| 456 a->Bind(&out); | 460 a->Bind(&out); |
| 457 return var_result.value(); | 461 return var_result.value(); |
| 458 } | 462 } |
| 459 | 463 |
| 460 } // namespace | 464 } // namespace |
| 461 | 465 |
| 462 // ES#sec-regexp.prototype.exec | |
| 463 // RegExp.prototype.exec ( string ) | |
| 464 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { | |
| 465 CodeStubAssembler a(state); | |
| 466 | |
| 467 Node* const maybe_receiver = a.Parameter(0); | |
| 468 Node* const maybe_string = a.Parameter(1); | |
| 469 Node* const context = a.Parameter(4); | |
| 470 | |
| 471 Node* const result = | |
| 472 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string); | |
| 473 a.Return(result); | |
| 474 } | |
| 475 | |
| 476 namespace { | 466 namespace { |
| 477 | 467 |
| 478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 468 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
| 479 Node* context, Node* value, | 469 Node* context, Node* value, |
| 480 MessageTemplate::Template msg_template, | 470 MessageTemplate::Template msg_template, |
| 481 char const* method_name) { | 471 char const* method_name) { |
| 482 CLabel out(a), throw_exception(a, CLabel::kDeferred); | 472 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
| 483 CVariable var_value_map(a, MachineRepresentation::kTagged); | 473 CVariable var_value_map(a, MachineRepresentation::kTagged); |
| 484 | 474 |
| 485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 475 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 Node* const native_context = a->LoadNativeContext(context); | 545 Node* const native_context = a->LoadNativeContext(context); |
| 556 Node* const initial_regexp_result_map = | 546 Node* const initial_regexp_result_map = |
| 557 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 547 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
| 558 | 548 |
| 559 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, | 549 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, |
| 560 if_ismodified); | 550 if_ismodified); |
| 561 } | 551 } |
| 562 | 552 |
| 563 } // namespace | 553 } // namespace |
| 564 | 554 |
| 555 // ES#sec-regexp.prototype.exec |
| 556 // RegExp.prototype.exec ( string ) |
| 557 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { |
| 558 CodeStubAssembler a(state); |
| 559 |
| 560 Node* const maybe_receiver = a.Parameter(0); |
| 561 Node* const maybe_string = a.Parameter(1); |
| 562 Node* const context = a.Parameter(4); |
| 563 |
| 564 // Ensure {maybe_receiver} is a JSRegExp. |
| 565 Node* const regexp_map = a.ThrowIfNotInstanceType( |
| 566 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); |
| 567 Node* const receiver = maybe_receiver; |
| 568 |
| 569 // Convert {maybe_string} to a String. |
| 570 Node* const string = a.ToString(context, maybe_string); |
| 571 |
| 572 CLabel if_isfastpath(&a), if_isslowpath(&a); |
| 573 a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath, |
| 574 &if_isslowpath); |
| 575 |
| 576 a.Bind(&if_isfastpath); |
| 577 { |
| 578 Node* const result = |
| 579 RegExpPrototypeExecBody(&a, context, receiver, string, true); |
| 580 a.Return(result); |
| 581 } |
| 582 |
| 583 a.Bind(&if_isslowpath); |
| 584 { |
| 585 Node* const result = |
| 586 RegExpPrototypeExecBody(&a, context, receiver, string, false); |
| 587 a.Return(result); |
| 588 } |
| 589 } |
| 590 |
| 565 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | 591 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
| 566 CodeStubAssembler a(state); | 592 CodeStubAssembler a(state); |
| 567 | 593 |
| 568 Node* const receiver = a.Parameter(0); | 594 Node* const receiver = a.Parameter(0); |
| 569 Node* const context = a.Parameter(3); | 595 Node* const context = a.Parameter(3); |
| 570 | 596 |
| 571 Isolate* isolate = a.isolate(); | 597 Isolate* isolate = a.isolate(); |
| 572 Node* const int_zero = a.IntPtrConstant(0); | 598 Node* const int_zero = a.IntPtrConstant(0); |
| 573 Node* const int_one = a.IntPtrConstant(1); | 599 Node* const int_one = a.IntPtrConstant(1); |
| 574 | 600 |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1026 namespace { | 1052 namespace { |
| 1027 | 1053 |
| 1028 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1054 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 1029 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, | 1055 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, |
| 1030 Node* string) { | 1056 Node* string) { |
| 1031 Isolate* isolate = a->isolate(); | 1057 Isolate* isolate = a->isolate(); |
| 1032 | 1058 |
| 1033 Node* const null = a->NullConstant(); | 1059 Node* const null = a->NullConstant(); |
| 1034 | 1060 |
| 1035 CVariable var_result(a, MachineRepresentation::kTagged); | 1061 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1036 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); | 1062 CLabel out(a), if_isfastpath(a), if_isslowpath(a); |
| 1037 | 1063 |
| 1038 Node* const map = a->LoadMap(recv); | 1064 Node* const map = a->LoadMap(recv); |
| 1039 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); | 1065 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath); |
| 1040 | 1066 |
| 1041 a->Bind(&call_builtin_exec); | 1067 a->Bind(&if_isfastpath); |
| 1042 { | 1068 { |
| 1043 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); | 1069 Node* const result = |
| 1070 RegExpPrototypeExecBody(a, context, recv, string, true); |
| 1044 var_result.Bind(result); | 1071 var_result.Bind(result); |
| 1045 a->Goto(&out); | 1072 a->Goto(&out); |
| 1046 } | 1073 } |
| 1047 | 1074 |
| 1048 a->Bind(&slow_path); | 1075 a->Bind(&if_isslowpath); |
| 1049 { | 1076 { |
| 1050 // Take the slow path of fetching the exec property, calling it, and | 1077 // Take the slow path of fetching the exec property, calling it, and |
| 1051 // verifying its return value. | 1078 // verifying its return value. |
| 1052 | 1079 |
| 1053 // Get the exec property. | 1080 // Get the exec property. |
| 1054 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); | 1081 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); |
| 1055 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 1082 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 1056 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); | 1083 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); |
| 1057 | 1084 |
| 1058 // Is {exec} callable? | 1085 // Is {exec} callable? |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1075 ThrowIfNotJSReceiver(a, isolate, context, result, | 1102 ThrowIfNotJSReceiver(a, isolate, context, result, |
| 1076 MessageTemplate::kInvalidRegExpExecResult, "unused"); | 1103 MessageTemplate::kInvalidRegExpExecResult, "unused"); |
| 1077 | 1104 |
| 1078 a->Goto(&out); | 1105 a->Goto(&out); |
| 1079 } | 1106 } |
| 1080 | 1107 |
| 1081 a->Bind(&if_isnotcallable); | 1108 a->Bind(&if_isnotcallable); |
| 1082 { | 1109 { |
| 1083 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, | 1110 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, |
| 1084 "RegExp.prototype.exec"); | 1111 "RegExp.prototype.exec"); |
| 1085 a->Goto(&call_builtin_exec); | 1112 |
| 1113 Node* const result = |
| 1114 RegExpPrototypeExecBody(a, context, recv, string, false); |
| 1115 var_result.Bind(result); |
| 1116 a->Goto(&out); |
| 1086 } | 1117 } |
| 1087 } | 1118 } |
| 1088 | 1119 |
| 1089 a->Bind(&out); | 1120 a->Bind(&out); |
| 1090 return var_result.value(); | 1121 return var_result.value(); |
| 1091 } | 1122 } |
| 1092 | 1123 |
| 1093 } // namespace | 1124 } // namespace |
| 1094 | 1125 |
| 1095 // ES#sec-regexp.prototype.test | 1126 // ES#sec-regexp.prototype.test |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1301 Node* const regexp = receiver; | 1332 Node* const regexp = receiver; |
| 1302 Node* const is_global = | 1333 Node* const is_global = |
| 1303 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); | 1334 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); |
| 1304 | 1335 |
| 1305 CLabel if_isglobal(a), if_isnotglobal(a); | 1336 CLabel if_isglobal(a), if_isnotglobal(a); |
| 1306 a->Branch(is_global, &if_isglobal, &if_isnotglobal); | 1337 a->Branch(is_global, &if_isglobal, &if_isnotglobal); |
| 1307 | 1338 |
| 1308 a->Bind(&if_isnotglobal); | 1339 a->Bind(&if_isnotglobal); |
| 1309 { | 1340 { |
| 1310 Node* const result = | 1341 Node* const result = |
| 1311 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1342 is_fastpath ? RegExpPrototypeExecBody(a, context, regexp, string, true) |
| 1312 : RegExpExec(a, context, regexp, string); | 1343 : RegExpExec(a, context, regexp, string); |
| 1313 a->Return(result); | 1344 a->Return(result); |
| 1314 } | 1345 } |
| 1315 | 1346 |
| 1316 a->Bind(&if_isglobal); | 1347 a->Bind(&if_isglobal); |
| 1317 { | 1348 { |
| 1318 Node* const is_unicode = | 1349 Node* const is_unicode = |
| 1319 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); | 1350 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); |
| 1320 | 1351 |
| 1321 if (is_fastpath) { | 1352 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
| 1322 FastStoreLastIndex(a, context, regexp, smi_zero); | |
| 1323 } else { | |
| 1324 SlowStoreLastIndex(a, context, regexp, smi_zero); | |
| 1325 } | |
| 1326 | 1353 |
| 1327 // Allocate an array to store the resulting match strings. | 1354 // Allocate an array to store the resulting match strings. |
| 1328 | 1355 |
| 1329 GrowableFixedArray array(a); | 1356 GrowableFixedArray array(a); |
| 1330 | 1357 |
| 1331 // Loop preparations. Within the loop, collect results from RegExpExec | 1358 // Loop preparations. Within the loop, collect results from RegExpExec |
| 1332 // and store match strings in the array. | 1359 // and store match strings in the array. |
| 1333 | 1360 |
| 1334 CVariable* vars[] = {array.var_array(), array.var_length(), | 1361 CVariable* vars[] = {array.var_array(), array.var_length(), |
| 1335 array.var_capacity()}; | 1362 array.var_capacity()}; |
| 1336 CLabel loop(a, 3, vars), out(a); | 1363 CLabel loop(a, 3, vars), out(a); |
| 1337 a->Goto(&loop); | 1364 a->Goto(&loop); |
| 1338 | 1365 |
| 1339 a->Bind(&loop); | 1366 a->Bind(&loop); |
| 1340 { | 1367 { |
| 1341 Node* const result = | 1368 Node* const result = is_fastpath ? RegExpPrototypeExecBody( |
| 1342 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1369 a, context, regexp, string, true) |
| 1343 : RegExpExec(a, context, regexp, string); | 1370 : RegExpExec(a, context, regexp, string); |
| 1344 | 1371 |
| 1345 CLabel if_didmatch(a), if_didnotmatch(a); | 1372 CLabel if_didmatch(a), if_didnotmatch(a); |
| 1346 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); | 1373 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); |
| 1347 | 1374 |
| 1348 a->Bind(&if_didnotmatch); | 1375 a->Bind(&if_didnotmatch); |
| 1349 { | 1376 { |
| 1350 // Return null if there were no matches, otherwise just exit the loop. | 1377 // Return null if there were no matches, otherwise just exit the loop. |
| 1351 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); | 1378 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); |
| 1352 a->Return(null); | 1379 a->Return(null); |
| 1353 } | 1380 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 | 1435 |
| 1409 // Store the match, growing the fixed array if needed. | 1436 // Store the match, growing the fixed array if needed. |
| 1410 | 1437 |
| 1411 array.Push(match); | 1438 array.Push(match); |
| 1412 | 1439 |
| 1413 // Advance last index if the match is the empty string. | 1440 // Advance last index if the match is the empty string. |
| 1414 | 1441 |
| 1415 Node* const match_length = a->LoadStringLength(match); | 1442 Node* const match_length = a->LoadStringLength(match); |
| 1416 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); | 1443 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); |
| 1417 | 1444 |
| 1418 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) | 1445 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath); |
| 1419 : SlowLoadLastIndex(a, context, regexp); | |
| 1420 | 1446 |
| 1421 Callable tolength_callable = CodeFactory::ToLength(isolate); | 1447 Callable tolength_callable = CodeFactory::ToLength(isolate); |
| 1422 last_index = a->CallStub(tolength_callable, context, last_index); | 1448 last_index = a->CallStub(tolength_callable, context, last_index); |
| 1423 | 1449 |
| 1424 Node* const new_last_index = | 1450 Node* const new_last_index = |
| 1425 AdvanceStringIndex(a, string, last_index, is_unicode); | 1451 AdvanceStringIndex(a, string, last_index, is_unicode); |
| 1426 | 1452 |
| 1427 if (is_fastpath) { | 1453 StoreLastIndex(a, context, regexp, new_last_index, is_fastpath); |
| 1428 FastStoreLastIndex(a, context, regexp, new_last_index); | |
| 1429 } else { | |
| 1430 SlowStoreLastIndex(a, context, regexp, new_last_index); | |
| 1431 } | |
| 1432 | 1454 |
| 1433 a->Goto(&loop); | 1455 a->Goto(&loop); |
| 1434 } | 1456 } |
| 1435 } | 1457 } |
| 1436 | 1458 |
| 1437 a->Bind(&out); | 1459 a->Bind(&out); |
| 1438 { | 1460 { |
| 1439 // Wrap the match in a JSArray. | 1461 // Wrap the match in a JSArray. |
| 1440 | 1462 |
| 1441 Node* const result = array.ToJSArray(context); | 1463 Node* const result = array.ToJSArray(context); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1479 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, | 1501 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
| 1480 Node* const receiver, | 1502 Node* const receiver, |
| 1481 Node* const string, Node* const context, | 1503 Node* const string, Node* const context, |
| 1482 bool is_fastpath) { | 1504 bool is_fastpath) { |
| 1483 Isolate* const isolate = a->isolate(); | 1505 Isolate* const isolate = a->isolate(); |
| 1484 | 1506 |
| 1485 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1507 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1486 | 1508 |
| 1487 // Grab the initial value of last index. | 1509 // Grab the initial value of last index. |
| 1488 Node* const previous_last_index = | 1510 Node* const previous_last_index = |
| 1489 is_fastpath ? FastLoadLastIndex(a, context, receiver) | 1511 LoadLastIndex(a, context, receiver, is_fastpath); |
| 1490 : SlowLoadLastIndex(a, context, receiver); | |
| 1491 | 1512 |
| 1492 // Ensure last index is 0. | 1513 // Ensure last index is 0. |
| 1493 if (is_fastpath) { | 1514 if (is_fastpath) { |
| 1494 FastStoreLastIndex(a, context, receiver, smi_zero); | 1515 FastStoreLastIndex(a, receiver, smi_zero); |
| 1495 } else { | 1516 } else { |
| 1496 CLabel next(a); | 1517 CLabel next(a); |
| 1497 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1518 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
| 1498 | 1519 |
| 1499 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1520 SlowStoreLastIndex(a, context, receiver, smi_zero); |
| 1500 a->Goto(&next); | 1521 a->Goto(&next); |
| 1501 a->Bind(&next); | 1522 a->Bind(&next); |
| 1502 } | 1523 } |
| 1503 | 1524 |
| 1504 // Call exec. | 1525 // Call exec. |
| 1505 Node* const match_indices = | 1526 Node* const match_indices = |
| 1506 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) | 1527 is_fastpath ? RegExpPrototypeExecBody(a, context, receiver, string, true) |
| 1507 : RegExpExec(a, context, receiver, string); | 1528 : RegExpExec(a, context, receiver, string); |
| 1508 | 1529 |
| 1509 // Reset last index if necessary. | 1530 // Reset last index if necessary. |
| 1510 if (is_fastpath) { | 1531 if (is_fastpath) { |
| 1511 FastStoreLastIndex(a, context, receiver, previous_last_index); | 1532 FastStoreLastIndex(a, receiver, previous_last_index); |
| 1512 } else { | 1533 } else { |
| 1513 CLabel next(a); | 1534 CLabel next(a); |
| 1514 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1535 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
| 1515 | 1536 |
| 1516 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1537 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
| 1517 &next); | 1538 &next); |
| 1518 | 1539 |
| 1519 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1540 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
| 1520 a->Goto(&next); | 1541 a->Goto(&next); |
| 1521 a->Bind(&next); | 1542 a->Bind(&next); |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1928 Node* const int_zero = a->IntPtrConstant(0); | 1949 Node* const int_zero = a->IntPtrConstant(0); |
| 1929 Node* const int_one = a->IntPtrConstant(1); | 1950 Node* const int_one = a->IntPtrConstant(1); |
| 1930 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1951 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1931 | 1952 |
| 1932 Node* const native_context = a->LoadNativeContext(context); | 1953 Node* const native_context = a->LoadNativeContext(context); |
| 1933 | 1954 |
| 1934 CLabel out(a); | 1955 CLabel out(a); |
| 1935 CVariable var_result(a, MachineRepresentation::kTagged); | 1956 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1936 | 1957 |
| 1937 // Set last index to 0. | 1958 // Set last index to 0. |
| 1938 FastStoreLastIndex(a, context, regexp, smi_zero); | 1959 FastStoreLastIndex(a, regexp, smi_zero); |
| 1939 | 1960 |
| 1940 // Allocate {result_array}. | 1961 // Allocate {result_array}. |
| 1941 Node* result_array; | 1962 Node* result_array; |
| 1942 { | 1963 { |
| 1943 ElementsKind kind = FAST_ELEMENTS; | 1964 ElementsKind kind = FAST_ELEMENTS; |
| 1944 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | 1965 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); |
| 1945 Node* const capacity = a->IntPtrConstant(16); | 1966 Node* const capacity = a->IntPtrConstant(16); |
| 1946 Node* const length = smi_zero; | 1967 Node* const length = smi_zero; |
| 1947 Node* const allocation_site = nullptr; | 1968 Node* const allocation_site = nullptr; |
| 1948 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1969 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 1949 | 1970 |
| 1950 result_array = a->AllocateJSArray(kind, array_map, capacity, length, | 1971 result_array = a->AllocateJSArray(kind, array_map, capacity, length, |
| 1951 allocation_site, capacity_mode); | 1972 allocation_site, capacity_mode); |
| 1952 } | 1973 } |
| 1953 | 1974 |
| 1954 // Call into runtime for RegExpExecMultiple. | 1975 // Call into runtime for RegExpExecMultiple. |
| 1955 Node* last_match_info = a->LoadContextElement( | 1976 Node* last_match_info = a->LoadContextElement( |
| 1956 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1977 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 1957 Node* const res = | 1978 Node* const res = |
| 1958 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, | 1979 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, |
| 1959 subject_string, last_match_info, result_array); | 1980 subject_string, last_match_info, result_array); |
| 1960 | 1981 |
| 1961 // Reset last index to 0. | 1982 // Reset last index to 0. |
| 1962 FastStoreLastIndex(a, context, regexp, smi_zero); | 1983 FastStoreLastIndex(a, regexp, smi_zero); |
| 1963 | 1984 |
| 1964 // If no matches, return the subject string. | 1985 // If no matches, return the subject string. |
| 1965 var_result.Bind(subject_string); | 1986 var_result.Bind(subject_string); |
| 1966 a->GotoIf(a->WordEqual(res, null), &out); | 1987 a->GotoIf(a->WordEqual(res, null), &out); |
| 1967 | 1988 |
| 1968 // Reload last match info since it might have changed. | 1989 // Reload last match info since it might have changed. |
| 1969 last_match_info = a->LoadContextElement( | 1990 last_match_info = a->LoadContextElement( |
| 1970 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1991 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 1971 | 1992 |
| 1972 Node* const res_length = a->LoadJSArrayLength(res); | 1993 Node* const res_length = a->LoadJSArrayLength(res); |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2155 // Is {regexp} global? | 2176 // Is {regexp} global? |
| 2156 CLabel if_isglobal(a), if_isnonglobal(a); | 2177 CLabel if_isglobal(a), if_isnonglobal(a); |
| 2157 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 2178 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 2158 Node* const is_global = | 2179 Node* const is_global = |
| 2159 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); | 2180 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); |
| 2160 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); | 2181 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); |
| 2161 | 2182 |
| 2162 a->Bind(&if_isglobal); | 2183 a->Bind(&if_isglobal); |
| 2163 { | 2184 { |
| 2164 // Hand off global regexps to runtime. | 2185 // Hand off global regexps to runtime. |
| 2165 FastStoreLastIndex(a, context, regexp, smi_zero); | 2186 FastStoreLastIndex(a, regexp, smi_zero); |
| 2166 Node* const result = | 2187 Node* const result = |
| 2167 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, | 2188 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, |
| 2168 subject_string, regexp, replace_string, last_match_info); | 2189 subject_string, regexp, replace_string, last_match_info); |
| 2169 var_result.Bind(result); | 2190 var_result.Bind(result); |
| 2170 a->Goto(&out); | 2191 a->Goto(&out); |
| 2171 } | 2192 } |
| 2172 | 2193 |
| 2173 a->Bind(&if_isnonglobal); | 2194 a->Bind(&if_isnonglobal); |
| 2174 { | 2195 { |
| 2175 // Run exec, then manually construct the resulting string. | 2196 // Run exec, then manually construct the resulting string. |
| 2176 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2197 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 2177 Node* const match_indices = | 2198 Node* const match_indices = |
| 2178 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, | 2199 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, |
| 2179 last_match_info); | 2200 last_match_info); |
| 2180 | 2201 |
| 2181 CLabel if_matched(a), if_didnotmatch(a); | 2202 CLabel if_matched(a), if_didnotmatch(a); |
| 2182 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2203 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
| 2183 | 2204 |
| 2184 a->Bind(&if_didnotmatch); | 2205 a->Bind(&if_didnotmatch); |
| 2185 { | 2206 { |
| 2186 FastStoreLastIndex(a, context, regexp, smi_zero); | 2207 FastStoreLastIndex(a, regexp, smi_zero); |
| 2187 var_result.Bind(subject_string); | 2208 var_result.Bind(subject_string); |
| 2188 a->Goto(&out); | 2209 a->Goto(&out); |
| 2189 } | 2210 } |
| 2190 | 2211 |
| 2191 a->Bind(&if_matched); | 2212 a->Bind(&if_matched); |
| 2192 { | 2213 { |
| 2193 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 2214 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 2194 | 2215 |
| 2195 Node* const subject_start = smi_zero; | 2216 Node* const subject_start = smi_zero; |
| 2196 Node* const match_start = a->LoadFixedArrayElement( | 2217 Node* const match_start = a->LoadFixedArrayElement( |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2366 a.Bind(&if_matched); | 2387 a.Bind(&if_matched); |
| 2367 { | 2388 { |
| 2368 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2389 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
| 2369 match_indices, string); | 2390 match_indices, string); |
| 2370 a.Return(result); | 2391 a.Return(result); |
| 2371 } | 2392 } |
| 2372 } | 2393 } |
| 2373 | 2394 |
| 2374 } // namespace internal | 2395 } // namespace internal |
| 2375 } // namespace v8 | 2396 } // namespace v8 |
| OLD | NEW |