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-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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 a->Bind(&next_iter); | 290 a->Bind(&next_iter); |
| 320 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); | 291 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); |
| 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 Node* Generate_RegExpPrototypeExecBodyWithoutResult( |
|
Igor Sheludko
2016/11/30 22:04:21
Please add a comment (especially about what does t
jgruber
2016/12/01 09:09:09
Done.
| |
| 330 // RegExp.prototype.exec ( string ) | 301 CodeStubAssembler* a, Node* const context, Node* const regexp, |
| 331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, | 302 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) { |
| 332 Node* maybe_receiver, Node* maybe_string) { | |
| 333 Isolate* const isolate = a->isolate(); | 303 Isolate* const isolate = a->isolate(); |
| 334 | 304 |
| 335 Node* const null = a->NullConstant(); | 305 Node* const null = a->NullConstant(); |
| 336 Node* const int_zero = a->IntPtrConstant(0); | 306 Node* const int_zero = a->IntPtrConstant(0); |
| 337 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 307 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 338 | 308 |
| 309 if (!is_fastpath) { | |
| 310 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | |
| 311 "RegExp.prototype.exec"); | |
| 312 } | |
| 313 | |
| 314 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string))); | |
| 315 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE)); | |
| 316 | |
| 339 CVariable var_result(a, MachineRepresentation::kTagged); | 317 CVariable var_result(a, MachineRepresentation::kTagged); |
| 340 CLabel out(a); | 318 CLabel out(a); |
| 341 | 319 |
| 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); | 320 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); | 321 Node* const string_length = a->LoadStringLength(string); |
| 359 | 322 |
| 360 // Check whether the regexp is global or sticky, which determines whether we | 323 // Check whether the regexp is global or sticky, which determines whether we |
| 361 // update last index later on. | 324 // update last index later on. |
| 362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 325 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 363 Node* const is_global_or_sticky = | 326 Node* const is_global_or_sticky = |
| 364 a->WordAnd(a->SmiUntag(flags), | 327 a->WordAnd(a->SmiUntag(flags), |
| 365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 328 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
| 366 Node* const should_update_last_index = | 329 Node* const should_update_last_index = |
| 367 a->WordNotEqual(is_global_or_sticky, int_zero); | 330 a->WordNotEqual(is_global_or_sticky, int_zero); |
| 368 | 331 |
| 369 // Grab and possibly update last index. | 332 // Grab and possibly update last index. |
| 370 CLabel run_exec(a); | 333 CLabel run_exec(a); |
| 371 CVariable var_lastindex(a, MachineRepresentation::kTagged); | 334 CVariable var_lastindex(a, MachineRepresentation::kTagged); |
| 372 { | 335 { |
| 373 CLabel if_doupdate(a), if_dontupdate(a); | 336 CLabel if_doupdate(a), if_dontupdate(a); |
| 374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); | 337 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); |
| 375 | 338 |
| 376 a->Bind(&if_doupdate); | 339 a->Bind(&if_doupdate); |
| 377 { | 340 { |
| 378 Node* const regexp_lastindex = | 341 Node* const regexp_lastindex = |
| 379 LoadLastIndex(a, context, has_initialmap, regexp); | 342 LoadLastIndex(a, context, regexp, is_fastpath); |
| 343 var_lastindex.Bind(regexp_lastindex); | |
| 380 | 344 |
| 381 Callable tolength_callable = CodeFactory::ToLength(isolate); | 345 // Omit ToLength if lastindex is a non-negative smi. |
| 382 Node* const lastindex = | 346 { |
| 383 a->CallStub(tolength_callable, context, regexp_lastindex); | 347 CLabel call_tolength(a, CLabel::kDeferred), next(a); |
| 384 var_lastindex.Bind(lastindex); | 348 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next, |
| 349 &call_tolength); | |
| 350 | |
| 351 a->Bind(&call_tolength); | |
| 352 { | |
| 353 Callable tolength_callable = CodeFactory::ToLength(isolate); | |
| 354 var_lastindex.Bind( | |
| 355 a->CallStub(tolength_callable, context, regexp_lastindex)); | |
| 356 a->Goto(&next); | |
| 357 } | |
| 358 | |
| 359 a->Bind(&next); | |
| 360 } | |
| 361 | |
| 362 Node* const lastindex = var_lastindex.value(); | |
| 385 | 363 |
| 386 CLabel if_isoob(a, CLabel::kDeferred); | 364 CLabel if_isoob(a, CLabel::kDeferred); |
| 387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); | 365 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); |
| 388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); | 366 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); |
| 389 a->Goto(&run_exec); | 367 a->Goto(&run_exec); |
| 390 | 368 |
| 391 a->Bind(&if_isoob); | 369 a->Bind(&if_isoob); |
| 392 { | 370 { |
| 393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 371 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
| 394 var_result.Bind(null); | 372 var_result.Bind(null); |
| 395 a->Goto(&out); | 373 a->Goto(if_didnotmatch); |
| 396 } | 374 } |
| 397 } | 375 } |
| 398 | 376 |
| 399 a->Bind(&if_dontupdate); | 377 a->Bind(&if_dontupdate); |
| 400 { | 378 { |
| 401 var_lastindex.Bind(smi_zero); | 379 var_lastindex.Bind(smi_zero); |
| 402 a->Goto(&run_exec); | 380 a->Goto(&run_exec); |
| 403 } | 381 } |
| 404 } | 382 } |
| 405 | 383 |
| 406 Node* match_indices; | 384 Node* match_indices; |
| 407 CLabel successful_match(a); | 385 CLabel successful_match(a); |
| 408 a->Bind(&run_exec); | 386 a->Bind(&run_exec); |
| 409 { | 387 { |
| 410 // Get last match info from the context. | 388 // Get last match info from the context. |
| 411 Node* const last_match_info = a->LoadContextElement( | 389 Node* const last_match_info = a->LoadContextElement( |
| 412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 390 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 413 | 391 |
| 414 // Call the exec stub. | 392 // Call the exec stub. |
| 415 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 393 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 416 match_indices = a->CallStub(exec_callable, context, regexp, string, | 394 match_indices = a->CallStub(exec_callable, context, regexp, string, |
| 417 var_lastindex.value(), last_match_info); | 395 var_lastindex.value(), last_match_info); |
| 396 var_result.Bind(match_indices); | |
| 418 | 397 |
| 419 // {match_indices} is either null or the RegExpMatchInfo array. | 398 // {match_indices} is either null or the RegExpMatchInfo array. |
| 420 // Return early if exec failed, possibly updating last index. | 399 // Return early if exec failed, possibly updating last index. |
| 421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 400 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
| 422 | 401 |
| 423 CLabel return_null(a); | 402 a->GotoUnless(should_update_last_index, if_didnotmatch); |
| 424 a->GotoUnless(should_update_last_index, &return_null); | |
| 425 | 403 |
| 426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 404 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
| 427 a->Goto(&return_null); | 405 a->Goto(if_didnotmatch); |
| 428 | |
| 429 a->Bind(&return_null); | |
| 430 var_result.Bind(null); | |
| 431 a->Goto(&out); | |
| 432 } | 406 } |
| 433 | 407 |
| 434 CLabel construct_result(a); | |
| 435 a->Bind(&successful_match); | 408 a->Bind(&successful_match); |
| 436 { | 409 { |
| 437 a->GotoUnless(should_update_last_index, &construct_result); | 410 a->GotoUnless(should_update_last_index, &out); |
| 438 | 411 |
| 439 // Update the new last index from {match_indices}. | 412 // Update the new last index from {match_indices}. |
| 440 Node* const new_lastindex = a->LoadFixedArrayElement( | 413 Node* const new_lastindex = a->LoadFixedArrayElement( |
| 441 match_indices, | 414 match_indices, |
| 442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | 415 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
| 443 | 416 |
| 444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 417 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); |
| 445 a->Goto(&construct_result); | 418 a->Goto(&out); |
| 419 } | |
| 446 | 420 |
| 447 a->Bind(&construct_result); | 421 a->Bind(&out); |
| 448 { | 422 return var_result.value(); |
| 449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 423 } |
| 450 match_indices, string); | 424 |
| 451 var_result.Bind(result); | 425 // ES#sec-regexp.prototype.exec |
| 452 a->Goto(&out); | 426 // RegExp.prototype.exec ( string ) |
| 453 } | 427 Node* Generate_RegExpPrototypeExecBody(CodeStubAssembler* a, |
|
Igor Sheludko
2016/11/30 22:12:08
I think you can drop the Generate_ prefix for read
jgruber
2016/12/01 09:09:09
Done.
| |
| 428 Node* const context, Node* const regexp, | |
| 429 Node* const string, | |
| 430 const bool is_fastpath) { | |
| 431 Isolate* const isolate = a->isolate(); | |
| 432 Node* const null = a->NullConstant(); | |
| 433 | |
| 434 CVariable var_result(a, MachineRepresentation::kTagged); | |
| 435 | |
| 436 CLabel if_didnotmatch(a), out(a); | |
| 437 Node* const indices_or_null = Generate_RegExpPrototypeExecBodyWithoutResult( | |
| 438 a, context, regexp, string, &if_didnotmatch, is_fastpath); | |
| 439 | |
| 440 // Successful match. | |
| 441 { | |
| 442 Node* const match_indices = indices_or_null; | |
| 443 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context, | |
| 444 match_indices, string); | |
| 445 var_result.Bind(result); | |
| 446 a->Goto(&out); | |
| 447 } | |
| 448 | |
| 449 a->Bind(&if_didnotmatch); | |
| 450 { | |
| 451 var_result.Bind(null); | |
| 452 a->Goto(&out); | |
| 454 } | 453 } |
| 455 | 454 |
| 456 a->Bind(&out); | 455 a->Bind(&out); |
| 457 return var_result.value(); | 456 return var_result.value(); |
| 458 } | 457 } |
| 459 | 458 |
| 460 } // namespace | 459 } // namespace |
| 461 | 460 |
| 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 { | 461 namespace { |
| 477 | 462 |
| 478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 463 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
| 479 Node* context, Node* value, | 464 Node* context, Node* value, |
| 480 MessageTemplate::Template msg_template, | 465 MessageTemplate::Template msg_template, |
| 481 char const* method_name) { | 466 char const* method_name) { |
| 482 CLabel out(a), throw_exception(a, CLabel::kDeferred); | 467 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
| 483 CVariable var_value_map(a, MachineRepresentation::kTagged); | 468 CVariable var_value_map(a, MachineRepresentation::kTagged); |
| 484 | 469 |
| 485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 470 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); | 540 Node* const native_context = a->LoadNativeContext(context); |
| 556 Node* const initial_regexp_result_map = | 541 Node* const initial_regexp_result_map = |
| 557 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 542 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
| 558 | 543 |
| 559 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, | 544 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, |
| 560 if_ismodified); | 545 if_ismodified); |
| 561 } | 546 } |
| 562 | 547 |
| 563 } // namespace | 548 } // namespace |
| 564 | 549 |
| 550 // ES#sec-regexp.prototype.exec | |
| 551 // RegExp.prototype.exec ( string ) | |
| 552 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { | |
| 553 CodeStubAssembler a(state); | |
| 554 | |
| 555 Node* const maybe_receiver = a.Parameter(0); | |
| 556 Node* const maybe_string = a.Parameter(1); | |
| 557 Node* const context = a.Parameter(4); | |
| 558 | |
| 559 // Ensure {maybe_receiver} is a JSRegExp. | |
| 560 Node* const regexp_map = a.ThrowIfNotInstanceType( | |
| 561 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | |
| 562 Node* const receiver = maybe_receiver; | |
| 563 | |
| 564 // Convert {maybe_string} to a String. | |
| 565 Node* const string = a.ToString(context, maybe_string); | |
| 566 | |
| 567 CLabel if_isfastpath(&a), if_isslowpath(&a); | |
| 568 a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath, | |
| 569 &if_isslowpath); | |
| 570 | |
| 571 a.Bind(&if_isfastpath); | |
| 572 { | |
| 573 Node* const result = | |
| 574 Generate_RegExpPrototypeExecBody(&a, context, receiver, string, true); | |
| 575 a.Return(result); | |
| 576 } | |
| 577 | |
| 578 a.Bind(&if_isslowpath); | |
| 579 { | |
| 580 Node* const result = | |
| 581 Generate_RegExpPrototypeExecBody(&a, context, receiver, string, false); | |
| 582 a.Return(result); | |
| 583 } | |
| 584 } | |
| 585 | |
| 565 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | 586 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
| 566 CodeStubAssembler a(state); | 587 CodeStubAssembler a(state); |
| 567 | 588 |
| 568 Node* const receiver = a.Parameter(0); | 589 Node* const receiver = a.Parameter(0); |
| 569 Node* const context = a.Parameter(3); | 590 Node* const context = a.Parameter(3); |
| 570 | 591 |
| 571 Isolate* isolate = a.isolate(); | 592 Isolate* isolate = a.isolate(); |
| 572 Node* const int_zero = a.IntPtrConstant(0); | 593 Node* const int_zero = a.IntPtrConstant(0); |
| 573 Node* const int_one = a.IntPtrConstant(1); | 594 Node* const int_one = a.IntPtrConstant(1); |
| 574 | 595 |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1026 namespace { | 1047 namespace { |
| 1027 | 1048 |
| 1028 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1049 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 1029 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, | 1050 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, |
| 1030 Node* string) { | 1051 Node* string) { |
| 1031 Isolate* isolate = a->isolate(); | 1052 Isolate* isolate = a->isolate(); |
| 1032 | 1053 |
| 1033 Node* const null = a->NullConstant(); | 1054 Node* const null = a->NullConstant(); |
| 1034 | 1055 |
| 1035 CVariable var_result(a, MachineRepresentation::kTagged); | 1056 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1036 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); | 1057 CLabel out(a), if_isfastpath(a), if_isslowpath(a); |
| 1037 | 1058 |
| 1038 Node* const map = a->LoadMap(recv); | 1059 Node* const map = a->LoadMap(recv); |
| 1039 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); | 1060 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath); |
| 1040 | 1061 |
| 1041 a->Bind(&call_builtin_exec); | 1062 a->Bind(&if_isfastpath); |
| 1042 { | 1063 { |
| 1043 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); | 1064 Node* const result = |
| 1065 Generate_RegExpPrototypeExecBody(a, context, recv, string, true); | |
| 1044 var_result.Bind(result); | 1066 var_result.Bind(result); |
| 1045 a->Goto(&out); | 1067 a->Goto(&out); |
| 1046 } | 1068 } |
| 1047 | 1069 |
| 1048 a->Bind(&slow_path); | 1070 a->Bind(&if_isslowpath); |
| 1049 { | 1071 { |
| 1050 // Take the slow path of fetching the exec property, calling it, and | 1072 // Take the slow path of fetching the exec property, calling it, and |
| 1051 // verifying its return value. | 1073 // verifying its return value. |
| 1052 | 1074 |
| 1053 // Get the exec property. | 1075 // Get the exec property. |
| 1054 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); | 1076 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); |
| 1055 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 1077 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 1056 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); | 1078 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); |
| 1057 | 1079 |
| 1058 // Is {exec} callable? | 1080 // Is {exec} callable? |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1075 ThrowIfNotJSReceiver(a, isolate, context, result, | 1097 ThrowIfNotJSReceiver(a, isolate, context, result, |
| 1076 MessageTemplate::kInvalidRegExpExecResult, "unused"); | 1098 MessageTemplate::kInvalidRegExpExecResult, "unused"); |
| 1077 | 1099 |
| 1078 a->Goto(&out); | 1100 a->Goto(&out); |
| 1079 } | 1101 } |
| 1080 | 1102 |
| 1081 a->Bind(&if_isnotcallable); | 1103 a->Bind(&if_isnotcallable); |
| 1082 { | 1104 { |
| 1083 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, | 1105 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, |
| 1084 "RegExp.prototype.exec"); | 1106 "RegExp.prototype.exec"); |
| 1085 a->Goto(&call_builtin_exec); | 1107 |
| 1108 Node* const result = | |
| 1109 Generate_RegExpPrototypeExecBody(a, context, recv, string, false); | |
| 1110 var_result.Bind(result); | |
| 1111 a->Goto(&out); | |
| 1086 } | 1112 } |
| 1087 } | 1113 } |
| 1088 | 1114 |
| 1089 a->Bind(&out); | 1115 a->Bind(&out); |
| 1090 return var_result.value(); | 1116 return var_result.value(); |
| 1091 } | 1117 } |
| 1092 | 1118 |
| 1093 } // namespace | 1119 } // namespace |
| 1094 | 1120 |
| 1095 // ES#sec-regexp.prototype.test | 1121 // ES#sec-regexp.prototype.test |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1300 | 1326 |
| 1301 Node* const regexp = receiver; | 1327 Node* const regexp = receiver; |
| 1302 Node* const is_global = | 1328 Node* const is_global = |
| 1303 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); | 1329 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); |
| 1304 | 1330 |
| 1305 CLabel if_isglobal(a), if_isnotglobal(a); | 1331 CLabel if_isglobal(a), if_isnotglobal(a); |
| 1306 a->Branch(is_global, &if_isglobal, &if_isnotglobal); | 1332 a->Branch(is_global, &if_isglobal, &if_isnotglobal); |
| 1307 | 1333 |
| 1308 a->Bind(&if_isnotglobal); | 1334 a->Bind(&if_isnotglobal); |
| 1309 { | 1335 { |
| 1310 Node* const result = | 1336 Node* const result = is_fastpath ? Generate_RegExpPrototypeExecBody( |
| 1311 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1337 a, context, regexp, string, true) |
| 1312 : RegExpExec(a, context, regexp, string); | 1338 : RegExpExec(a, context, regexp, string); |
| 1313 a->Return(result); | 1339 a->Return(result); |
| 1314 } | 1340 } |
| 1315 | 1341 |
| 1316 a->Bind(&if_isglobal); | 1342 a->Bind(&if_isglobal); |
| 1317 { | 1343 { |
| 1318 Node* const is_unicode = | 1344 Node* const is_unicode = |
| 1319 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); | 1345 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); |
| 1320 | 1346 |
| 1321 if (is_fastpath) { | 1347 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 | 1348 |
| 1327 // Allocate an array to store the resulting match strings. | 1349 // Allocate an array to store the resulting match strings. |
| 1328 | 1350 |
| 1329 GrowableFixedArray array(a); | 1351 GrowableFixedArray array(a); |
| 1330 | 1352 |
| 1331 // Loop preparations. Within the loop, collect results from RegExpExec | 1353 // Loop preparations. Within the loop, collect results from RegExpExec |
| 1332 // and store match strings in the array. | 1354 // and store match strings in the array. |
| 1333 | 1355 |
| 1334 CVariable* vars[] = {array.var_array(), array.var_length(), | 1356 CVariable* vars[] = {array.var_array(), array.var_length(), |
| 1335 array.var_capacity()}; | 1357 array.var_capacity()}; |
| 1336 CLabel loop(a, 3, vars), out(a); | 1358 CLabel loop(a, 3, vars), out(a); |
| 1337 a->Goto(&loop); | 1359 a->Goto(&loop); |
| 1338 | 1360 |
| 1339 a->Bind(&loop); | 1361 a->Bind(&loop); |
| 1340 { | 1362 { |
| 1341 Node* const result = | 1363 Node* const result = is_fastpath ? Generate_RegExpPrototypeExecBody( |
| 1342 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | 1364 a, context, regexp, string, true) |
| 1343 : RegExpExec(a, context, regexp, string); | 1365 : RegExpExec(a, context, regexp, string); |
| 1344 | 1366 |
| 1345 CLabel if_didmatch(a), if_didnotmatch(a); | 1367 CLabel if_didmatch(a), if_didnotmatch(a); |
| 1346 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); | 1368 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); |
| 1347 | 1369 |
| 1348 a->Bind(&if_didnotmatch); | 1370 a->Bind(&if_didnotmatch); |
| 1349 { | 1371 { |
| 1350 // Return null if there were no matches, otherwise just exit the loop. | 1372 // Return null if there were no matches, otherwise just exit the loop. |
| 1351 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); | 1373 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); |
| 1352 a->Return(null); | 1374 a->Return(null); |
| 1353 } | 1375 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1408 | 1430 |
| 1409 // Store the match, growing the fixed array if needed. | 1431 // Store the match, growing the fixed array if needed. |
| 1410 | 1432 |
| 1411 array.Push(match); | 1433 array.Push(match); |
| 1412 | 1434 |
| 1413 // Advance last index if the match is the empty string. | 1435 // Advance last index if the match is the empty string. |
| 1414 | 1436 |
| 1415 Node* const match_length = a->LoadStringLength(match); | 1437 Node* const match_length = a->LoadStringLength(match); |
| 1416 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); | 1438 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); |
| 1417 | 1439 |
| 1418 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) | 1440 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath); |
| 1419 : SlowLoadLastIndex(a, context, regexp); | |
| 1420 | 1441 |
| 1421 Callable tolength_callable = CodeFactory::ToLength(isolate); | 1442 Callable tolength_callable = CodeFactory::ToLength(isolate); |
| 1422 last_index = a->CallStub(tolength_callable, context, last_index); | 1443 last_index = a->CallStub(tolength_callable, context, last_index); |
| 1423 | 1444 |
| 1424 Node* const new_last_index = | 1445 Node* const new_last_index = |
| 1425 AdvanceStringIndex(a, string, last_index, is_unicode); | 1446 AdvanceStringIndex(a, string, last_index, is_unicode); |
| 1426 | 1447 |
| 1427 if (is_fastpath) { | 1448 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 | 1449 |
| 1433 a->Goto(&loop); | 1450 a->Goto(&loop); |
| 1434 } | 1451 } |
| 1435 } | 1452 } |
| 1436 | 1453 |
| 1437 a->Bind(&out); | 1454 a->Bind(&out); |
| 1438 { | 1455 { |
| 1439 // Wrap the match in a JSArray. | 1456 // Wrap the match in a JSArray. |
| 1440 | 1457 |
| 1441 Node* const result = array.ToJSArray(context); | 1458 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, | 1496 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
| 1480 Node* const receiver, | 1497 Node* const receiver, |
| 1481 Node* const string, Node* const context, | 1498 Node* const string, Node* const context, |
| 1482 bool is_fastpath) { | 1499 bool is_fastpath) { |
| 1483 Isolate* const isolate = a->isolate(); | 1500 Isolate* const isolate = a->isolate(); |
| 1484 | 1501 |
| 1485 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1502 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1486 | 1503 |
| 1487 // Grab the initial value of last index. | 1504 // Grab the initial value of last index. |
| 1488 Node* const previous_last_index = | 1505 Node* const previous_last_index = |
| 1489 is_fastpath ? FastLoadLastIndex(a, context, receiver) | 1506 LoadLastIndex(a, context, receiver, is_fastpath); |
| 1490 : SlowLoadLastIndex(a, context, receiver); | |
| 1491 | 1507 |
| 1492 // Ensure last index is 0. | 1508 // Ensure last index is 0. |
| 1493 if (is_fastpath) { | 1509 if (is_fastpath) { |
| 1494 FastStoreLastIndex(a, context, receiver, smi_zero); | 1510 FastStoreLastIndex(a, receiver, smi_zero); |
| 1495 } else { | 1511 } else { |
| 1496 CLabel next(a); | 1512 CLabel next(a); |
| 1497 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1513 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
| 1498 | 1514 |
| 1499 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1515 SlowStoreLastIndex(a, context, receiver, smi_zero); |
| 1500 a->Goto(&next); | 1516 a->Goto(&next); |
| 1501 a->Bind(&next); | 1517 a->Bind(&next); |
| 1502 } | 1518 } |
| 1503 | 1519 |
| 1504 // Call exec. | 1520 // Call exec. |
| 1505 Node* const match_indices = | 1521 Node* const match_indices = |
| 1506 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) | 1522 is_fastpath |
| 1507 : RegExpExec(a, context, receiver, string); | 1523 ? Generate_RegExpPrototypeExecBody(a, context, receiver, string, true) |
| 1524 : RegExpExec(a, context, receiver, string); | |
| 1508 | 1525 |
| 1509 // Reset last index if necessary. | 1526 // Reset last index if necessary. |
| 1510 if (is_fastpath) { | 1527 if (is_fastpath) { |
| 1511 FastStoreLastIndex(a, context, receiver, previous_last_index); | 1528 FastStoreLastIndex(a, receiver, previous_last_index); |
| 1512 } else { | 1529 } else { |
| 1513 CLabel next(a); | 1530 CLabel next(a); |
| 1514 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1531 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
| 1515 | 1532 |
| 1516 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1533 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
| 1517 &next); | 1534 &next); |
| 1518 | 1535 |
| 1519 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1536 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
| 1520 a->Goto(&next); | 1537 a->Goto(&next); |
| 1521 a->Bind(&next); | 1538 a->Bind(&next); |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1927 Node* const int_zero = a->IntPtrConstant(0); | 1944 Node* const int_zero = a->IntPtrConstant(0); |
| 1928 Node* const int_one = a->IntPtrConstant(1); | 1945 Node* const int_one = a->IntPtrConstant(1); |
| 1929 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1946 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1930 | 1947 |
| 1931 Node* const native_context = a->LoadNativeContext(context); | 1948 Node* const native_context = a->LoadNativeContext(context); |
| 1932 | 1949 |
| 1933 CLabel out(a); | 1950 CLabel out(a); |
| 1934 CVariable var_result(a, MachineRepresentation::kTagged); | 1951 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1935 | 1952 |
| 1936 // Set last index to 0. | 1953 // Set last index to 0. |
| 1937 FastStoreLastIndex(a, context, regexp, smi_zero); | 1954 FastStoreLastIndex(a, regexp, smi_zero); |
| 1938 | 1955 |
| 1939 // Allocate {result_array}. | 1956 // Allocate {result_array}. |
| 1940 Node* result_array; | 1957 Node* result_array; |
| 1941 { | 1958 { |
| 1942 ElementsKind kind = FAST_ELEMENTS; | 1959 ElementsKind kind = FAST_ELEMENTS; |
| 1943 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | 1960 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); |
| 1944 Node* const capacity = a->IntPtrConstant(16); | 1961 Node* const capacity = a->IntPtrConstant(16); |
| 1945 Node* const length = smi_zero; | 1962 Node* const length = smi_zero; |
| 1946 Node* const allocation_site = nullptr; | 1963 Node* const allocation_site = nullptr; |
| 1947 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1964 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 1948 | 1965 |
| 1949 result_array = a->AllocateJSArray(kind, array_map, capacity, length, | 1966 result_array = a->AllocateJSArray(kind, array_map, capacity, length, |
| 1950 allocation_site, capacity_mode); | 1967 allocation_site, capacity_mode); |
| 1951 } | 1968 } |
| 1952 | 1969 |
| 1953 // Call into runtime for RegExpExecMultiple. | 1970 // Call into runtime for RegExpExecMultiple. |
| 1954 Node* last_match_info = a->LoadContextElement( | 1971 Node* last_match_info = a->LoadContextElement( |
| 1955 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1972 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 1956 Node* const res = | 1973 Node* const res = |
| 1957 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, | 1974 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, |
| 1958 subject_string, last_match_info, result_array); | 1975 subject_string, last_match_info, result_array); |
| 1959 | 1976 |
| 1960 // Reset last index to 0. | 1977 // Reset last index to 0. |
| 1961 FastStoreLastIndex(a, context, regexp, smi_zero); | 1978 FastStoreLastIndex(a, regexp, smi_zero); |
| 1962 | 1979 |
| 1963 // If no matches, return the subject string. | 1980 // If no matches, return the subject string. |
| 1964 var_result.Bind(subject_string); | 1981 var_result.Bind(subject_string); |
| 1965 a->GotoIf(a->WordEqual(res, null), &out); | 1982 a->GotoIf(a->WordEqual(res, null), &out); |
| 1966 | 1983 |
| 1967 // Reload last match info since it might have changed. | 1984 // Reload last match info since it might have changed. |
| 1968 last_match_info = a->LoadContextElement( | 1985 last_match_info = a->LoadContextElement( |
| 1969 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1986 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 1970 | 1987 |
| 1971 Node* const res_length = a->LoadJSArrayLength(res); | 1988 Node* const res_length = a->LoadJSArrayLength(res); |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2154 // Is {regexp} global? | 2171 // Is {regexp} global? |
| 2155 CLabel if_isglobal(a), if_isnonglobal(a); | 2172 CLabel if_isglobal(a), if_isnonglobal(a); |
| 2156 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 2173 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 2157 Node* const is_global = | 2174 Node* const is_global = |
| 2158 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); | 2175 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); |
| 2159 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); | 2176 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); |
| 2160 | 2177 |
| 2161 a->Bind(&if_isglobal); | 2178 a->Bind(&if_isglobal); |
| 2162 { | 2179 { |
| 2163 // Hand off global regexps to runtime. | 2180 // Hand off global regexps to runtime. |
| 2164 FastStoreLastIndex(a, context, regexp, smi_zero); | 2181 FastStoreLastIndex(a, regexp, smi_zero); |
| 2165 Node* const result = | 2182 Node* const result = |
| 2166 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, | 2183 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, |
| 2167 subject_string, regexp, replace_string, last_match_info); | 2184 subject_string, regexp, replace_string, last_match_info); |
| 2168 var_result.Bind(result); | 2185 var_result.Bind(result); |
| 2169 a->Goto(&out); | 2186 a->Goto(&out); |
| 2170 } | 2187 } |
| 2171 | 2188 |
| 2172 a->Bind(&if_isnonglobal); | 2189 a->Bind(&if_isnonglobal); |
| 2173 { | 2190 { |
| 2174 // Run exec, then manually construct the resulting string. | 2191 // Run exec, then manually construct the resulting string. |
| 2175 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2192 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 2176 Node* const match_indices = | 2193 Node* const match_indices = |
| 2177 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, | 2194 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, |
| 2178 last_match_info); | 2195 last_match_info); |
| 2179 | 2196 |
| 2180 CLabel if_matched(a), if_didnotmatch(a); | 2197 CLabel if_matched(a), if_didnotmatch(a); |
| 2181 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2198 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
| 2182 | 2199 |
| 2183 a->Bind(&if_didnotmatch); | 2200 a->Bind(&if_didnotmatch); |
| 2184 { | 2201 { |
| 2185 FastStoreLastIndex(a, context, regexp, smi_zero); | 2202 FastStoreLastIndex(a, regexp, smi_zero); |
| 2186 var_result.Bind(subject_string); | 2203 var_result.Bind(subject_string); |
| 2187 a->Goto(&out); | 2204 a->Goto(&out); |
| 2188 } | 2205 } |
| 2189 | 2206 |
| 2190 a->Bind(&if_matched); | 2207 a->Bind(&if_matched); |
| 2191 { | 2208 { |
| 2192 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 2209 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 2193 | 2210 |
| 2194 Node* const subject_start = smi_zero; | 2211 Node* const subject_start = smi_zero; |
| 2195 Node* const match_start = a->LoadFixedArrayElement( | 2212 Node* const match_start = a->LoadFixedArrayElement( |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2365 a.Bind(&if_matched); | 2382 a.Bind(&if_matched); |
| 2366 { | 2383 { |
| 2367 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2384 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
| 2368 match_indices, string); | 2385 match_indices, string); |
| 2369 a.Return(result); | 2386 a.Return(result); |
| 2370 } | 2387 } |
| 2371 } | 2388 } |
| 2372 | 2389 |
| 2373 } // namespace internal | 2390 } // namespace internal |
| 2374 } // namespace v8 | 2391 } // namespace v8 |
| OLD | NEW |