| 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" |
| 11 #include "src/string-builder.h" | 11 #include "src/string-builder.h" |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 | 15 |
| 16 typedef compiler::Node Node; |
| 17 typedef CodeStubAssembler::Label CLabel; |
| 18 typedef CodeStubAssembler::Variable CVariable; |
| 19 typedef compiler::CodeAssemblerState CodeAssemblerState; |
| 20 |
| 16 // ----------------------------------------------------------------------------- | 21 // ----------------------------------------------------------------------------- |
| 17 // ES6 section 21.2 RegExp Objects | 22 // ES6 section 21.2 RegExp Objects |
| 18 | 23 |
| 19 namespace { | 24 namespace { |
| 20 | 25 |
| 21 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { | 26 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { |
| 22 static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; | 27 static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; |
| 23 char flags_string[kMaxFlagsLength]; | 28 char flags_string[kMaxFlagsLength]; |
| 24 int i = 0; | 29 int i = 0; |
| 25 | 30 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); | 168 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); |
| 164 | 169 |
| 165 // Return undefined for compatibility with JSC. | 170 // Return undefined for compatibility with JSC. |
| 166 // See http://crbug.com/585775 for web compat details. | 171 // See http://crbug.com/585775 for web compat details. |
| 167 | 172 |
| 168 return isolate->heap()->undefined_value(); | 173 return isolate->heap()->undefined_value(); |
| 169 } | 174 } |
| 170 | 175 |
| 171 namespace { | 176 namespace { |
| 172 | 177 |
| 173 compiler::Node* FastLoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 178 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
| 174 compiler::Node* regexp) { | |
| 175 // Load the in-object field. | 179 // Load the in-object field. |
| 176 static const int field_offset = | 180 static const int field_offset = |
| 177 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 181 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 178 return a->LoadObjectField(regexp, field_offset); | 182 return a->LoadObjectField(regexp, field_offset); |
| 179 } | 183 } |
| 180 | 184 |
| 181 compiler::Node* SlowLoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 185 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
| 182 compiler::Node* regexp) { | |
| 183 // Load through the GetProperty stub. | 186 // Load through the GetProperty stub. |
| 184 typedef compiler::Node Node; | |
| 185 | |
| 186 Node* const name = | 187 Node* const name = |
| 187 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 188 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
| 188 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 189 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 189 return a->CallStub(getproperty_callable, context, regexp, name); | 190 return a->CallStub(getproperty_callable, context, regexp, name); |
| 190 } | 191 } |
| 191 | 192 |
| 192 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 193 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, |
| 193 compiler::Node* has_initialmap, | 194 Node* regexp) { |
| 194 compiler::Node* regexp) { | 195 CVariable var_value(a, MachineRepresentation::kTagged); |
| 195 typedef CodeStubAssembler::Variable Variable; | |
| 196 typedef CodeStubAssembler::Label Label; | |
| 197 | 196 |
| 198 Variable var_value(a, MachineRepresentation::kTagged); | 197 CLabel out(a), if_unmodified(a), if_modified(a); |
| 199 | |
| 200 Label out(a), if_unmodified(a), if_modified(a); | |
| 201 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 198 a->Branch(has_initialmap, &if_unmodified, &if_modified); |
| 202 | 199 |
| 203 a->Bind(&if_unmodified); | 200 a->Bind(&if_unmodified); |
| 204 { | 201 { |
| 205 var_value.Bind(FastLoadLastIndex(a, context, regexp)); | 202 var_value.Bind(FastLoadLastIndex(a, context, regexp)); |
| 206 a->Goto(&out); | 203 a->Goto(&out); |
| 207 } | 204 } |
| 208 | 205 |
| 209 a->Bind(&if_modified); | 206 a->Bind(&if_modified); |
| 210 { | 207 { |
| 211 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); | 208 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); |
| 212 a->Goto(&out); | 209 a->Goto(&out); |
| 213 } | 210 } |
| 214 | 211 |
| 215 a->Bind(&out); | 212 a->Bind(&out); |
| 216 return var_value.value(); | 213 return var_value.value(); |
| 217 } | 214 } |
| 218 | 215 |
| 219 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified | 216 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified |
| 220 // JSRegExp instance. | 217 // JSRegExp instance. |
| 221 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 218 void FastStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
| 222 compiler::Node* regexp, compiler::Node* value) { | 219 Node* value) { |
| 223 // Store the in-object field. | 220 // Store the in-object field. |
| 224 static const int field_offset = | 221 static const int field_offset = |
| 225 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 222 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 226 a->StoreObjectField(regexp, field_offset, value); | 223 a->StoreObjectField(regexp, field_offset, value); |
| 227 } | 224 } |
| 228 | 225 |
| 229 void SlowStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 226 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
| 230 compiler::Node* regexp, compiler::Node* value) { | 227 Node* value) { |
| 231 // Store through runtime. | 228 // Store through runtime. |
| 232 // TODO(ishell): Use SetPropertyStub here once available. | 229 // TODO(ishell): Use SetPropertyStub here once available. |
| 233 typedef compiler::Node Node; | |
| 234 | |
| 235 Node* const name = | 230 Node* const name = |
| 236 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 231 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
| 237 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); | 232 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); |
| 238 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, | 233 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, |
| 239 language_mode); | 234 language_mode); |
| 240 } | 235 } |
| 241 | 236 |
| 242 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 237 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, |
| 243 compiler::Node* has_initialmap, compiler::Node* regexp, | 238 Node* regexp, Node* value) { |
| 244 compiler::Node* value) { | 239 CLabel out(a), if_unmodified(a), if_modified(a); |
| 245 typedef CodeStubAssembler::Label Label; | |
| 246 | |
| 247 Label out(a), if_unmodified(a), if_modified(a); | |
| 248 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 240 a->Branch(has_initialmap, &if_unmodified, &if_modified); |
| 249 | 241 |
| 250 a->Bind(&if_unmodified); | 242 a->Bind(&if_unmodified); |
| 251 { | 243 { |
| 252 FastStoreLastIndex(a, context, regexp, value); | 244 FastStoreLastIndex(a, context, regexp, value); |
| 253 a->Goto(&out); | 245 a->Goto(&out); |
| 254 } | 246 } |
| 255 | 247 |
| 256 a->Bind(&if_modified); | 248 a->Bind(&if_modified); |
| 257 { | 249 { |
| 258 SlowStoreLastIndex(a, context, regexp, value); | 250 SlowStoreLastIndex(a, context, regexp, value); |
| 259 a->Goto(&out); | 251 a->Goto(&out); |
| 260 } | 252 } |
| 261 | 253 |
| 262 a->Bind(&out); | 254 a->Bind(&out); |
| 263 } | 255 } |
| 264 | 256 |
| 265 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, | 257 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, |
| 266 CodeStubAssembler* a, | 258 Node* context, Node* match_info, |
| 267 compiler::Node* context, | 259 Node* string) { |
| 268 compiler::Node* match_info, | 260 CLabel out(a); |
| 269 compiler::Node* string) { | |
| 270 typedef CodeStubAssembler::Variable Variable; | |
| 271 typedef CodeStubAssembler::Label Label; | |
| 272 typedef compiler::Node Node; | |
| 273 | |
| 274 Label out(a); | |
| 275 | 261 |
| 276 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 262 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 277 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( | 263 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( |
| 278 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, | 264 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, |
| 279 mode)); | 265 mode)); |
| 280 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); | 266 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); |
| 281 Node* const start = a->LoadFixedArrayElement( | 267 Node* const start = a->LoadFixedArrayElement( |
| 282 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), 0, | 268 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), 0, |
| 283 mode); | 269 mode); |
| 284 Node* const end = a->LoadFixedArrayElement( | 270 Node* const end = a->LoadFixedArrayElement( |
| (...skipping 10 matching lines...) Expand all Loading... |
| 295 | 281 |
| 296 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first, | 282 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first, |
| 297 SKIP_WRITE_BARRIER); | 283 SKIP_WRITE_BARRIER); |
| 298 | 284 |
| 299 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); | 285 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); |
| 300 | 286 |
| 301 // Store all remaining captures. | 287 // Store all remaining captures. |
| 302 Node* const limit = a->IntPtrAdd( | 288 Node* const limit = a->IntPtrAdd( |
| 303 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); | 289 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); |
| 304 | 290 |
| 305 Variable var_from_cursor(a, MachineType::PointerRepresentation()); | 291 CVariable var_from_cursor(a, MachineType::PointerRepresentation()); |
| 306 Variable var_to_cursor(a, MachineType::PointerRepresentation()); | 292 CVariable var_to_cursor(a, MachineType::PointerRepresentation()); |
| 307 | 293 |
| 308 var_from_cursor.Bind( | 294 var_from_cursor.Bind( |
| 309 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); | 295 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); |
| 310 var_to_cursor.Bind(a->IntPtrConstant(1)); | 296 var_to_cursor.Bind(a->IntPtrConstant(1)); |
| 311 | 297 |
| 312 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; | 298 CVariable* vars[] = {&var_from_cursor, &var_to_cursor}; |
| 313 Label loop(a, 2, vars); | 299 CLabel loop(a, 2, vars); |
| 314 | 300 |
| 315 a->Goto(&loop); | 301 a->Goto(&loop); |
| 316 a->Bind(&loop); | 302 a->Bind(&loop); |
| 317 { | 303 { |
| 318 Node* const from_cursor = var_from_cursor.value(); | 304 Node* const from_cursor = var_from_cursor.value(); |
| 319 Node* const to_cursor = var_to_cursor.value(); | 305 Node* const to_cursor = var_to_cursor.value(); |
| 320 Node* const start = a->LoadFixedArrayElement(match_info, from_cursor); | 306 Node* const start = a->LoadFixedArrayElement(match_info, from_cursor); |
| 321 | 307 |
| 322 Label next_iter(a); | 308 CLabel next_iter(a); |
| 323 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); | 309 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); |
| 324 | 310 |
| 325 Node* const from_cursor_plus1 = | 311 Node* const from_cursor_plus1 = |
| 326 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); | 312 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); |
| 327 Node* const end = a->LoadFixedArrayElement(match_info, from_cursor_plus1); | 313 Node* const end = a->LoadFixedArrayElement(match_info, from_cursor_plus1); |
| 328 | 314 |
| 329 Node* const capture = a->SubString(context, string, start, end); | 315 Node* const capture = a->SubString(context, string, start, end); |
| 330 a->StoreFixedArrayElement(result_elements, to_cursor, capture); | 316 a->StoreFixedArrayElement(result_elements, to_cursor, capture); |
| 331 a->Goto(&next_iter); | 317 a->Goto(&next_iter); |
| 332 | 318 |
| 333 a->Bind(&next_iter); | 319 a->Bind(&next_iter); |
| 334 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); | 320 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); |
| 335 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); | 321 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); |
| 336 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); | 322 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); |
| 337 } | 323 } |
| 338 | 324 |
| 339 a->Bind(&out); | 325 a->Bind(&out); |
| 340 return result; | 326 return result; |
| 341 } | 327 } |
| 342 | 328 |
| 343 // ES#sec-regexp.prototype.exec | 329 // ES#sec-regexp.prototype.exec |
| 344 // RegExp.prototype.exec ( string ) | 330 // RegExp.prototype.exec ( string ) |
| 345 compiler::Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, | 331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, |
| 346 compiler::Node* context, | 332 Node* maybe_receiver, Node* maybe_string) { |
| 347 compiler::Node* maybe_receiver, | |
| 348 compiler::Node* maybe_string) { | |
| 349 typedef CodeStubAssembler::Variable Variable; | |
| 350 typedef CodeStubAssembler::Label Label; | |
| 351 typedef compiler::Node Node; | |
| 352 | |
| 353 Isolate* const isolate = a->isolate(); | 333 Isolate* const isolate = a->isolate(); |
| 354 | 334 |
| 355 Node* const null = a->NullConstant(); | 335 Node* const null = a->NullConstant(); |
| 356 Node* const int_zero = a->IntPtrConstant(0); | 336 Node* const int_zero = a->IntPtrConstant(0); |
| 357 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 337 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 358 | 338 |
| 359 Variable var_result(a, MachineRepresentation::kTagged); | 339 CVariable var_result(a, MachineRepresentation::kTagged); |
| 360 Label out(a); | 340 CLabel out(a); |
| 361 | 341 |
| 362 // Ensure {maybe_receiver} is a JSRegExp. | 342 // Ensure {maybe_receiver} is a JSRegExp. |
| 363 Node* const regexp_map = a->ThrowIfNotInstanceType( | 343 Node* const regexp_map = a->ThrowIfNotInstanceType( |
| 364 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | 344 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); |
| 365 Node* const regexp = maybe_receiver; | 345 Node* const regexp = maybe_receiver; |
| 366 | 346 |
| 367 // Check whether the regexp instance is unmodified. | 347 // Check whether the regexp instance is unmodified. |
| 368 Node* const native_context = a->LoadNativeContext(context); | 348 Node* const native_context = a->LoadNativeContext(context); |
| 369 Node* const regexp_fun = | 349 Node* const regexp_fun = |
| 370 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 350 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
| 371 Node* const initial_map = | 351 Node* const initial_map = |
| 372 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 352 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 373 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map); | 353 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map); |
| 374 | 354 |
| 375 // Convert {maybe_string} to a string. | 355 // Convert {maybe_string} to a string. |
| 376 Callable tostring_callable = CodeFactory::ToString(isolate); | 356 Callable tostring_callable = CodeFactory::ToString(isolate); |
| 377 Node* const string = a->CallStub(tostring_callable, context, maybe_string); | 357 Node* const string = a->CallStub(tostring_callable, context, maybe_string); |
| 378 Node* const string_length = a->LoadStringLength(string); | 358 Node* const string_length = a->LoadStringLength(string); |
| 379 | 359 |
| 380 // Check whether the regexp is global or sticky, which determines whether we | 360 // Check whether the regexp is global or sticky, which determines whether we |
| 381 // update last index later on. | 361 // update last index later on. |
| 382 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 383 Node* const is_global_or_sticky = | 363 Node* const is_global_or_sticky = |
| 384 a->WordAnd(a->SmiUntag(flags), | 364 a->WordAnd(a->SmiUntag(flags), |
| 385 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
| 386 Node* const should_update_last_index = | 366 Node* const should_update_last_index = |
| 387 a->WordNotEqual(is_global_or_sticky, int_zero); | 367 a->WordNotEqual(is_global_or_sticky, int_zero); |
| 388 | 368 |
| 389 // Grab and possibly update last index. | 369 // Grab and possibly update last index. |
| 390 Label run_exec(a); | 370 CLabel run_exec(a); |
| 391 Variable var_lastindex(a, MachineRepresentation::kTagged); | 371 CVariable var_lastindex(a, MachineRepresentation::kTagged); |
| 392 { | 372 { |
| 393 Label if_doupdate(a), if_dontupdate(a); | 373 CLabel if_doupdate(a), if_dontupdate(a); |
| 394 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); | 374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); |
| 395 | 375 |
| 396 a->Bind(&if_doupdate); | 376 a->Bind(&if_doupdate); |
| 397 { | 377 { |
| 398 Node* const regexp_lastindex = | 378 Node* const regexp_lastindex = |
| 399 LoadLastIndex(a, context, has_initialmap, regexp); | 379 LoadLastIndex(a, context, has_initialmap, regexp); |
| 400 | 380 |
| 401 Callable tolength_callable = CodeFactory::ToLength(isolate); | 381 Callable tolength_callable = CodeFactory::ToLength(isolate); |
| 402 Node* const lastindex = | 382 Node* const lastindex = |
| 403 a->CallStub(tolength_callable, context, regexp_lastindex); | 383 a->CallStub(tolength_callable, context, regexp_lastindex); |
| 404 var_lastindex.Bind(lastindex); | 384 var_lastindex.Bind(lastindex); |
| 405 | 385 |
| 406 Label if_isoob(a, Label::kDeferred); | 386 CLabel if_isoob(a, CLabel::kDeferred); |
| 407 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); | 387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); |
| 408 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); | 388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); |
| 409 a->Goto(&run_exec); | 389 a->Goto(&run_exec); |
| 410 | 390 |
| 411 a->Bind(&if_isoob); | 391 a->Bind(&if_isoob); |
| 412 { | 392 { |
| 413 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); |
| 414 var_result.Bind(null); | 394 var_result.Bind(null); |
| 415 a->Goto(&out); | 395 a->Goto(&out); |
| 416 } | 396 } |
| 417 } | 397 } |
| 418 | 398 |
| 419 a->Bind(&if_dontupdate); | 399 a->Bind(&if_dontupdate); |
| 420 { | 400 { |
| 421 var_lastindex.Bind(smi_zero); | 401 var_lastindex.Bind(smi_zero); |
| 422 a->Goto(&run_exec); | 402 a->Goto(&run_exec); |
| 423 } | 403 } |
| 424 } | 404 } |
| 425 | 405 |
| 426 Node* match_indices; | 406 Node* match_indices; |
| 427 Label successful_match(a); | 407 CLabel successful_match(a); |
| 428 a->Bind(&run_exec); | 408 a->Bind(&run_exec); |
| 429 { | 409 { |
| 430 // Get last match info from the context. | 410 // Get last match info from the context. |
| 431 Node* const last_match_info = a->LoadContextElement( | 411 Node* const last_match_info = a->LoadContextElement( |
| 432 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 433 | 413 |
| 434 // Call the exec stub. | 414 // Call the exec stub. |
| 435 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 415 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 436 match_indices = a->CallStub(exec_callable, context, regexp, string, | 416 match_indices = a->CallStub(exec_callable, context, regexp, string, |
| 437 var_lastindex.value(), last_match_info); | 417 var_lastindex.value(), last_match_info); |
| 438 | 418 |
| 439 // {match_indices} is either null or the RegExpMatchInfo array. | 419 // {match_indices} is either null or the RegExpMatchInfo array. |
| 440 // Return early if exec failed, possibly updating last index. | 420 // Return early if exec failed, possibly updating last index. |
| 441 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
| 442 | 422 |
| 443 Label return_null(a); | 423 CLabel return_null(a); |
| 444 a->GotoUnless(should_update_last_index, &return_null); | 424 a->GotoUnless(should_update_last_index, &return_null); |
| 445 | 425 |
| 446 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); |
| 447 a->Goto(&return_null); | 427 a->Goto(&return_null); |
| 448 | 428 |
| 449 a->Bind(&return_null); | 429 a->Bind(&return_null); |
| 450 var_result.Bind(null); | 430 var_result.Bind(null); |
| 451 a->Goto(&out); | 431 a->Goto(&out); |
| 452 } | 432 } |
| 453 | 433 |
| 454 Label construct_result(a); | 434 CLabel construct_result(a); |
| 455 a->Bind(&successful_match); | 435 a->Bind(&successful_match); |
| 456 { | 436 { |
| 457 a->GotoUnless(should_update_last_index, &construct_result); | 437 a->GotoUnless(should_update_last_index, &construct_result); |
| 458 | 438 |
| 459 // Update the new last index from {match_indices}. | 439 // Update the new last index from {match_indices}. |
| 460 Node* const new_lastindex = a->LoadFixedArrayElement( | 440 Node* const new_lastindex = a->LoadFixedArrayElement( |
| 461 match_indices, | 441 match_indices, |
| 462 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | 442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
| 463 | 443 |
| 464 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); |
| 465 a->Goto(&construct_result); | 445 a->Goto(&construct_result); |
| 466 | 446 |
| 467 a->Bind(&construct_result); | 447 a->Bind(&construct_result); |
| 468 { | 448 { |
| 469 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
| 470 match_indices, string); | 450 match_indices, string); |
| 471 var_result.Bind(result); | 451 var_result.Bind(result); |
| 472 a->Goto(&out); | 452 a->Goto(&out); |
| 473 } | 453 } |
| 474 } | 454 } |
| 475 | 455 |
| 476 a->Bind(&out); | 456 a->Bind(&out); |
| 477 return var_result.value(); | 457 return var_result.value(); |
| 478 } | 458 } |
| 479 | 459 |
| 480 } // namespace | 460 } // namespace |
| 481 | 461 |
| 482 // ES#sec-regexp.prototype.exec | 462 // ES#sec-regexp.prototype.exec |
| 483 // RegExp.prototype.exec ( string ) | 463 // RegExp.prototype.exec ( string ) |
| 484 void Builtins::Generate_RegExpPrototypeExec( | 464 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { |
| 485 compiler::CodeAssemblerState* state) { | |
| 486 typedef compiler::Node Node; | |
| 487 CodeStubAssembler a(state); | 465 CodeStubAssembler a(state); |
| 488 | 466 |
| 489 Node* const maybe_receiver = a.Parameter(0); | 467 Node* const maybe_receiver = a.Parameter(0); |
| 490 Node* const maybe_string = a.Parameter(1); | 468 Node* const maybe_string = a.Parameter(1); |
| 491 Node* const context = a.Parameter(4); | 469 Node* const context = a.Parameter(4); |
| 492 | 470 |
| 493 Node* const result = | 471 Node* const result = |
| 494 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string); | 472 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string); |
| 495 a.Return(result); | 473 a.Return(result); |
| 496 } | 474 } |
| 497 | 475 |
| 498 namespace { | 476 namespace { |
| 499 | 477 |
| 500 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
| 501 compiler::Node* context, | 479 Node* context, Node* value, |
| 502 compiler::Node* value, | 480 MessageTemplate::Template msg_template, |
| 503 MessageTemplate::Template msg_template, | 481 char const* method_name) { |
| 504 char const* method_name) { | 482 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
| 505 typedef compiler::Node Node; | 483 CVariable var_value_map(a, MachineRepresentation::kTagged); |
| 506 typedef CodeStubAssembler::Label Label; | |
| 507 typedef CodeStubAssembler::Variable Variable; | |
| 508 | |
| 509 Label out(a), throw_exception(a, Label::kDeferred); | |
| 510 Variable var_value_map(a, MachineRepresentation::kTagged); | |
| 511 | 484 |
| 512 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
| 513 | 486 |
| 514 // Load the instance type of the {value}. | 487 // Load the instance type of the {value}. |
| 515 var_value_map.Bind(a->LoadMap(value)); | 488 var_value_map.Bind(a->LoadMap(value)); |
| 516 Node* const value_instance_type = | 489 Node* const value_instance_type = |
| 517 a->LoadMapInstanceType(var_value_map.value()); | 490 a->LoadMapInstanceType(var_value_map.value()); |
| 518 | 491 |
| 519 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, | 492 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, |
| 520 &throw_exception); | 493 &throw_exception); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 532 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, | 505 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, |
| 533 method_name_str, value_str); | 506 method_name_str, value_str); |
| 534 var_value_map.Bind(a->UndefinedConstant()); | 507 var_value_map.Bind(a->UndefinedConstant()); |
| 535 a->Goto(&out); // Never reached. | 508 a->Goto(&out); // Never reached. |
| 536 } | 509 } |
| 537 | 510 |
| 538 a->Bind(&out); | 511 a->Bind(&out); |
| 539 return var_value_map.value(); | 512 return var_value_map.value(); |
| 540 } | 513 } |
| 541 | 514 |
| 542 compiler::Node* IsInitialRegExpMap(CodeStubAssembler* a, | 515 Node* IsInitialRegExpMap(CodeStubAssembler* a, Node* context, Node* map) { |
| 543 compiler::Node* context, | |
| 544 compiler::Node* map) { | |
| 545 typedef compiler::Node Node; | |
| 546 | |
| 547 Node* const native_context = a->LoadNativeContext(context); | 516 Node* const native_context = a->LoadNativeContext(context); |
| 548 Node* const regexp_fun = | 517 Node* const regexp_fun = |
| 549 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 518 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
| 550 Node* const initial_map = | 519 Node* const initial_map = |
| 551 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 520 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 552 Node* const has_initialmap = a->WordEqual(map, initial_map); | 521 Node* const has_initialmap = a->WordEqual(map, initial_map); |
| 553 | 522 |
| 554 return has_initialmap; | 523 return has_initialmap; |
| 555 } | 524 } |
| 556 | 525 |
| 557 // RegExp fast path implementations rely on unmodified JSRegExp instances. | 526 // RegExp fast path implementations rely on unmodified JSRegExp instances. |
| 558 // We use a fairly coarse granularity for this and simply check whether both | 527 // We use a fairly coarse granularity for this and simply check whether both |
| 559 // the regexp itself is unmodified (i.e. its map has not changed) and its | 528 // the regexp itself is unmodified (i.e. its map has not changed) and its |
| 560 // prototype is unmodified. | 529 // prototype is unmodified. |
| 561 void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context, | 530 void BranchIfFastPath(CodeStubAssembler* a, Node* context, Node* map, |
| 562 compiler::Node* map, | 531 CLabel* if_isunmodified, CLabel* if_ismodified) { |
| 563 CodeStubAssembler::Label* if_isunmodified, | |
| 564 CodeStubAssembler::Label* if_ismodified) { | |
| 565 typedef compiler::Node Node; | |
| 566 | |
| 567 Node* const native_context = a->LoadNativeContext(context); | 532 Node* const native_context = a->LoadNativeContext(context); |
| 568 Node* const regexp_fun = | 533 Node* const regexp_fun = |
| 569 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 534 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
| 570 Node* const initial_map = | 535 Node* const initial_map = |
| 571 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 536 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 572 Node* const has_initialmap = a->WordEqual(map, initial_map); | 537 Node* const has_initialmap = a->WordEqual(map, initial_map); |
| 573 | 538 |
| 574 a->GotoUnless(has_initialmap, if_ismodified); | 539 a->GotoUnless(has_initialmap, if_ismodified); |
| 575 | 540 |
| 576 Node* const initial_proto_initial_map = a->LoadContextElement( | 541 Node* const initial_proto_initial_map = a->LoadContextElement( |
| 577 native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); | 542 native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); |
| 578 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); | 543 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); |
| 579 Node* const proto_has_initialmap = | 544 Node* const proto_has_initialmap = |
| 580 a->WordEqual(proto_map, initial_proto_initial_map); | 545 a->WordEqual(proto_map, initial_proto_initial_map); |
| 581 | 546 |
| 582 // TODO(ishell): Update this check once map changes for constant field | 547 // TODO(ishell): Update this check once map changes for constant field |
| 583 // tracking are landing. | 548 // tracking are landing. |
| 584 | 549 |
| 585 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); | 550 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
| 586 } | 551 } |
| 587 | 552 |
| 588 } // namespace | 553 } // namespace |
| 589 | 554 |
| 590 void Builtins::Generate_RegExpPrototypeFlagsGetter( | 555 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
| 591 compiler::CodeAssemblerState* state) { | |
| 592 typedef CodeStubAssembler::Variable Variable; | |
| 593 typedef CodeStubAssembler::Label Label; | |
| 594 typedef compiler::Node Node; | |
| 595 CodeStubAssembler a(state); | 556 CodeStubAssembler a(state); |
| 596 | 557 |
| 597 Node* const receiver = a.Parameter(0); | 558 Node* const receiver = a.Parameter(0); |
| 598 Node* const context = a.Parameter(3); | 559 Node* const context = a.Parameter(3); |
| 599 | 560 |
| 600 Isolate* isolate = a.isolate(); | 561 Isolate* isolate = a.isolate(); |
| 601 Node* const int_zero = a.IntPtrConstant(0); | 562 Node* const int_zero = a.IntPtrConstant(0); |
| 602 Node* const int_one = a.IntPtrConstant(1); | 563 Node* const int_one = a.IntPtrConstant(1); |
| 603 | 564 |
| 604 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver, | 565 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver, |
| 605 MessageTemplate::kRegExpNonObject, | 566 MessageTemplate::kRegExpNonObject, |
| 606 "RegExp.prototype.flags"); | 567 "RegExp.prototype.flags"); |
| 607 | 568 |
| 608 Variable var_length(&a, MachineType::PointerRepresentation()); | 569 CVariable var_length(&a, MachineType::PointerRepresentation()); |
| 609 Variable var_flags(&a, MachineType::PointerRepresentation()); | 570 CVariable var_flags(&a, MachineType::PointerRepresentation()); |
| 610 | 571 |
| 611 // First, count the number of characters we will need and check which flags | 572 // First, count the number of characters we will need and check which flags |
| 612 // are set. | 573 // are set. |
| 613 | 574 |
| 614 var_length.Bind(int_zero); | 575 var_length.Bind(int_zero); |
| 615 | 576 |
| 616 Label if_isunmodifiedjsregexp(&a), | 577 CLabel if_isunmodifiedjsregexp(&a), |
| 617 if_isnotunmodifiedjsregexp(&a, Label::kDeferred); | 578 if_isnotunmodifiedjsregexp(&a, CLabel::kDeferred); |
| 618 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp, | 579 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp, |
| 619 &if_isnotunmodifiedjsregexp); | 580 &if_isnotunmodifiedjsregexp); |
| 620 | 581 |
| 621 Label construct_string(&a); | 582 CLabel construct_string(&a); |
| 622 a.Bind(&if_isunmodifiedjsregexp); | 583 a.Bind(&if_isunmodifiedjsregexp); |
| 623 { | 584 { |
| 624 // Refer to JSRegExp's flag property on the fast-path. | 585 // Refer to JSRegExp's flag property on the fast-path. |
| 625 Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset); | 586 Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset); |
| 626 Node* const flags_intptr = a.SmiUntag(flags_smi); | 587 Node* const flags_intptr = a.SmiUntag(flags_smi); |
| 627 var_flags.Bind(flags_intptr); | 588 var_flags.Bind(flags_intptr); |
| 628 | 589 |
| 629 Label label_global(&a), label_ignorecase(&a), label_multiline(&a), | 590 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), |
| 630 label_unicode(&a), label_sticky(&a); | 591 label_unicode(&a), label_sticky(&a); |
| 631 | 592 |
| 632 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ | 593 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ |
| 633 do { \ | 594 do { \ |
| 634 a.Bind(&LABEL); \ | 595 a.Bind(&LABEL); \ |
| 635 Node* const mask = a.IntPtrConstant(FLAG); \ | 596 Node* const mask = a.IntPtrConstant(FLAG); \ |
| 636 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ | 597 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ |
| 637 &NEXT_LABEL); \ | 598 &NEXT_LABEL); \ |
| 638 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ | 599 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ |
| 639 a.Goto(&NEXT_LABEL); \ | 600 a.Goto(&NEXT_LABEL); \ |
| 640 } while (false) | 601 } while (false) |
| 641 | 602 |
| 642 a.Goto(&label_global); | 603 a.Goto(&label_global); |
| 643 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); | 604 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); |
| 644 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); | 605 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); |
| 645 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); | 606 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); |
| 646 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); | 607 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); |
| 647 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); | 608 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); |
| 648 #undef CASE_FOR_FLAG | 609 #undef CASE_FOR_FLAG |
| 649 } | 610 } |
| 650 | 611 |
| 651 a.Bind(&if_isnotunmodifiedjsregexp); | 612 a.Bind(&if_isnotunmodifiedjsregexp); |
| 652 { | 613 { |
| 653 // Fall back to GetProperty stub on the slow-path. | 614 // Fall back to GetProperty stub on the slow-path. |
| 654 var_flags.Bind(int_zero); | 615 var_flags.Bind(int_zero); |
| 655 | 616 |
| 656 Callable getproperty_callable = CodeFactory::GetProperty(a.isolate()); | 617 Callable getproperty_callable = CodeFactory::GetProperty(a.isolate()); |
| 657 Label label_global(&a), label_ignorecase(&a), label_multiline(&a), | 618 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), |
| 658 label_unicode(&a), label_sticky(&a); | 619 label_unicode(&a), label_sticky(&a); |
| 659 | 620 |
| 660 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ | 621 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ |
| 661 do { \ | 622 do { \ |
| 662 a.Bind(&LABEL); \ | 623 a.Bind(&LABEL); \ |
| 663 Node* const name = \ | 624 Node* const name = \ |
| 664 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ | 625 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ |
| 665 Node* const flag = \ | 626 Node* const flag = \ |
| 666 a.CallStub(getproperty_callable, context, receiver, name); \ | 627 a.CallStub(getproperty_callable, context, receiver, name); \ |
| 667 Label if_isflagset(&a); \ | 628 CLabel if_isflagset(&a); \ |
| 668 a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ | 629 a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ |
| 669 a.Bind(&if_isflagset); \ | 630 a.Bind(&if_isflagset); \ |
| 670 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ | 631 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ |
| 671 var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \ | 632 var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \ |
| 672 a.Goto(&NEXT_LABEL); \ | 633 a.Goto(&NEXT_LABEL); \ |
| 673 } while (false) | 634 } while (false) |
| 674 | 635 |
| 675 a.Goto(&label_global); | 636 a.Goto(&label_global); |
| 676 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); | 637 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); |
| 677 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, | 638 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, |
| 678 label_multiline); | 639 label_multiline); |
| 679 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, | 640 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, |
| 680 label_unicode); | 641 label_unicode); |
| 681 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); | 642 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); |
| 682 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); | 643 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); |
| 683 #undef CASE_FOR_FLAG | 644 #undef CASE_FOR_FLAG |
| 684 } | 645 } |
| 685 | 646 |
| 686 // Allocate a string of the required length and fill it with the corresponding | 647 // Allocate a string of the required length and fill it with the corresponding |
| 687 // char for each set flag. | 648 // char for each set flag. |
| 688 | 649 |
| 689 a.Bind(&construct_string); | 650 a.Bind(&construct_string); |
| 690 { | 651 { |
| 691 Node* const result = | 652 Node* const result = |
| 692 a.AllocateSeqOneByteString(context, var_length.value()); | 653 a.AllocateSeqOneByteString(context, var_length.value()); |
| 693 Node* const flags_intptr = var_flags.value(); | 654 Node* const flags_intptr = var_flags.value(); |
| 694 | 655 |
| 695 Variable var_offset(&a, MachineType::PointerRepresentation()); | 656 CVariable var_offset(&a, MachineType::PointerRepresentation()); |
| 696 var_offset.Bind( | 657 var_offset.Bind( |
| 697 a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 658 a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 698 | 659 |
| 699 Label label_global(&a), label_ignorecase(&a), label_multiline(&a), | 660 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), |
| 700 label_unicode(&a), label_sticky(&a), out(&a); | 661 label_unicode(&a), label_sticky(&a), out(&a); |
| 701 | 662 |
| 702 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ | 663 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ |
| 703 do { \ | 664 do { \ |
| 704 a.Bind(&LABEL); \ | 665 a.Bind(&LABEL); \ |
| 705 Node* const mask = a.IntPtrConstant(FLAG); \ | 666 Node* const mask = a.IntPtrConstant(FLAG); \ |
| 706 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ | 667 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ |
| 707 &NEXT_LABEL); \ | 668 &NEXT_LABEL); \ |
| 708 Node* const value = a.IntPtrConstant(CHAR); \ | 669 Node* const value = a.IntPtrConstant(CHAR); \ |
| 709 a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ | 670 a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 | 747 |
| 787 // ES6 21.2.4.2. | 748 // ES6 21.2.4.2. |
| 788 BUILTIN(RegExpPrototypeSpeciesGetter) { | 749 BUILTIN(RegExpPrototypeSpeciesGetter) { |
| 789 HandleScope scope(isolate); | 750 HandleScope scope(isolate); |
| 790 return *args.receiver(); | 751 return *args.receiver(); |
| 791 } | 752 } |
| 792 | 753 |
| 793 namespace { | 754 namespace { |
| 794 | 755 |
| 795 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. | 756 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. |
| 796 compiler::Node* FastFlagGetter(CodeStubAssembler* a, | 757 Node* FastFlagGetter(CodeStubAssembler* a, Node* const regexp, |
| 797 compiler::Node* const regexp, | 758 JSRegExp::Flag flag) { |
| 798 JSRegExp::Flag flag) { | |
| 799 typedef compiler::Node Node; | |
| 800 | |
| 801 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 759 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 802 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 760 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 803 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); | 761 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); |
| 804 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); | 762 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); |
| 805 | 763 |
| 806 return is_flag_set; | 764 return is_flag_set; |
| 807 } | 765 } |
| 808 | 766 |
| 809 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, | 767 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, |
| 810 v8::Isolate::UseCounterFeature counter, | 768 v8::Isolate::UseCounterFeature counter, |
| 811 const char* method_name) { | 769 const char* method_name) { |
| 812 typedef CodeStubAssembler::Label Label; | |
| 813 typedef compiler::Node Node; | |
| 814 | |
| 815 Node* const receiver = a->Parameter(0); | 770 Node* const receiver = a->Parameter(0); |
| 816 Node* const context = a->Parameter(3); | 771 Node* const context = a->Parameter(3); |
| 817 | 772 |
| 818 Isolate* isolate = a->isolate(); | 773 Isolate* isolate = a->isolate(); |
| 819 | 774 |
| 820 // Check whether we have an unmodified regexp instance. | 775 // Check whether we have an unmodified regexp instance. |
| 821 Label if_isunmodifiedjsregexp(a), | 776 CLabel if_isunmodifiedjsregexp(a), |
| 822 if_isnotunmodifiedjsregexp(a, Label::kDeferred); | 777 if_isnotunmodifiedjsregexp(a, CLabel::kDeferred); |
| 823 | 778 |
| 824 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); | 779 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); |
| 825 | 780 |
| 826 Node* const receiver_map = a->LoadMap(receiver); | 781 Node* const receiver_map = a->LoadMap(receiver); |
| 827 Node* const instance_type = a->LoadMapInstanceType(receiver_map); | 782 Node* const instance_type = a->LoadMapInstanceType(receiver_map); |
| 828 | 783 |
| 829 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)), | 784 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)), |
| 830 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp); | 785 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp); |
| 831 | 786 |
| 832 a->Bind(&if_isunmodifiedjsregexp); | 787 a->Bind(&if_isunmodifiedjsregexp); |
| 833 { | 788 { |
| 834 // Refer to JSRegExp's flag property on the fast-path. | 789 // Refer to JSRegExp's flag property on the fast-path. |
| 835 Node* const is_flag_set = FastFlagGetter(a, receiver, flag); | 790 Node* const is_flag_set = FastFlagGetter(a, receiver, flag); |
| 836 a->Return(a->Select(is_flag_set, a->TrueConstant(), a->FalseConstant())); | 791 a->Return(a->Select(is_flag_set, a->TrueConstant(), a->FalseConstant())); |
| 837 } | 792 } |
| 838 | 793 |
| 839 a->Bind(&if_isnotunmodifiedjsregexp); | 794 a->Bind(&if_isnotunmodifiedjsregexp); |
| 840 { | 795 { |
| 841 Node* const native_context = a->LoadNativeContext(context); | 796 Node* const native_context = a->LoadNativeContext(context); |
| 842 Node* const regexp_fun = | 797 Node* const regexp_fun = |
| 843 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 798 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
| 844 Node* const initial_map = a->LoadObjectField( | 799 Node* const initial_map = a->LoadObjectField( |
| 845 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 800 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 846 Node* const initial_prototype = a->LoadMapPrototype(initial_map); | 801 Node* const initial_prototype = a->LoadMapPrototype(initial_map); |
| 847 | 802 |
| 848 Label if_isprototype(a), if_isnotprototype(a); | 803 CLabel if_isprototype(a), if_isnotprototype(a); |
| 849 a->Branch(a->WordEqual(receiver, initial_prototype), &if_isprototype, | 804 a->Branch(a->WordEqual(receiver, initial_prototype), &if_isprototype, |
| 850 &if_isnotprototype); | 805 &if_isnotprototype); |
| 851 | 806 |
| 852 a->Bind(&if_isprototype); | 807 a->Bind(&if_isprototype); |
| 853 { | 808 { |
| 854 Node* const counter_smi = a->SmiConstant(Smi::FromInt(counter)); | 809 Node* const counter_smi = a->SmiConstant(Smi::FromInt(counter)); |
| 855 a->CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); | 810 a->CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); |
| 856 a->Return(a->UndefinedConstant()); | 811 a->Return(a->UndefinedConstant()); |
| 857 } | 812 } |
| 858 | 813 |
| 859 a->Bind(&if_isnotprototype); | 814 a->Bind(&if_isnotprototype); |
| 860 { | 815 { |
| 861 Node* const message_id = | 816 Node* const message_id = |
| 862 a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); | 817 a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); |
| 863 Node* const method_name_str = a->HeapConstant( | 818 Node* const method_name_str = a->HeapConstant( |
| 864 isolate->factory()->NewStringFromAsciiChecked(method_name)); | 819 isolate->factory()->NewStringFromAsciiChecked(method_name)); |
| 865 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, | 820 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, |
| 866 method_name_str); | 821 method_name_str); |
| 867 a->Return(a->UndefinedConstant()); // Never reached. | 822 a->Return(a->UndefinedConstant()); // Never reached. |
| 868 } | 823 } |
| 869 } | 824 } |
| 870 } | 825 } |
| 871 | 826 |
| 872 } // namespace | 827 } // namespace |
| 873 | 828 |
| 874 // ES6 21.2.5.4. | 829 // ES6 21.2.5.4. |
| 875 void Builtins::Generate_RegExpPrototypeGlobalGetter( | 830 void Builtins::Generate_RegExpPrototypeGlobalGetter(CodeAssemblerState* state) { |
| 876 compiler::CodeAssemblerState* state) { | |
| 877 CodeStubAssembler a(state); | 831 CodeStubAssembler a(state); |
| 878 Generate_FlagGetter(&a, JSRegExp::kGlobal, | 832 Generate_FlagGetter(&a, JSRegExp::kGlobal, |
| 879 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 833 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
| 880 "RegExp.prototype.global"); | 834 "RegExp.prototype.global"); |
| 881 } | 835 } |
| 882 | 836 |
| 883 // ES6 21.2.5.5. | 837 // ES6 21.2.5.5. |
| 884 void Builtins::Generate_RegExpPrototypeIgnoreCaseGetter( | 838 void Builtins::Generate_RegExpPrototypeIgnoreCaseGetter( |
| 885 compiler::CodeAssemblerState* state) { | 839 CodeAssemblerState* state) { |
| 886 CodeStubAssembler a(state); | 840 CodeStubAssembler a(state); |
| 887 Generate_FlagGetter(&a, JSRegExp::kIgnoreCase, | 841 Generate_FlagGetter(&a, JSRegExp::kIgnoreCase, |
| 888 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 842 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
| 889 "RegExp.prototype.ignoreCase"); | 843 "RegExp.prototype.ignoreCase"); |
| 890 } | 844 } |
| 891 | 845 |
| 892 // ES6 21.2.5.7. | 846 // ES6 21.2.5.7. |
| 893 void Builtins::Generate_RegExpPrototypeMultilineGetter( | 847 void Builtins::Generate_RegExpPrototypeMultilineGetter( |
| 894 compiler::CodeAssemblerState* state) { | 848 CodeAssemblerState* state) { |
| 895 CodeStubAssembler a(state); | 849 CodeStubAssembler a(state); |
| 896 Generate_FlagGetter(&a, JSRegExp::kMultiline, | 850 Generate_FlagGetter(&a, JSRegExp::kMultiline, |
| 897 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 851 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
| 898 "RegExp.prototype.multiline"); | 852 "RegExp.prototype.multiline"); |
| 899 } | 853 } |
| 900 | 854 |
| 901 // ES6 21.2.5.12. | 855 // ES6 21.2.5.12. |
| 902 void Builtins::Generate_RegExpPrototypeStickyGetter( | 856 void Builtins::Generate_RegExpPrototypeStickyGetter(CodeAssemblerState* state) { |
| 903 compiler::CodeAssemblerState* state) { | |
| 904 CodeStubAssembler a(state); | 857 CodeStubAssembler a(state); |
| 905 Generate_FlagGetter(&a, JSRegExp::kSticky, | 858 Generate_FlagGetter(&a, JSRegExp::kSticky, |
| 906 v8::Isolate::kRegExpPrototypeStickyGetter, | 859 v8::Isolate::kRegExpPrototypeStickyGetter, |
| 907 "RegExp.prototype.sticky"); | 860 "RegExp.prototype.sticky"); |
| 908 } | 861 } |
| 909 | 862 |
| 910 // ES6 21.2.5.15. | 863 // ES6 21.2.5.15. |
| 911 void Builtins::Generate_RegExpPrototypeUnicodeGetter( | 864 void Builtins::Generate_RegExpPrototypeUnicodeGetter( |
| 912 compiler::CodeAssemblerState* state) { | 865 CodeAssemblerState* state) { |
| 913 CodeStubAssembler a(state); | 866 CodeStubAssembler a(state); |
| 914 Generate_FlagGetter(&a, JSRegExp::kUnicode, | 867 Generate_FlagGetter(&a, JSRegExp::kUnicode, |
| 915 v8::Isolate::kRegExpPrototypeUnicodeGetter, | 868 v8::Isolate::kRegExpPrototypeUnicodeGetter, |
| 916 "RegExp.prototype.unicode"); | 869 "RegExp.prototype.unicode"); |
| 917 } | 870 } |
| 918 | 871 |
| 919 // The properties $1..$9 are the first nine capturing substrings of the last | 872 // The properties $1..$9 are the first nine capturing substrings of the last |
| 920 // successful match, or ''. The function RegExpMakeCaptureGetter will be | 873 // successful match, or ''. The function RegExpMakeCaptureGetter will be |
| 921 // called with indices from 1 to 9. | 874 // called with indices from 1 to 9. |
| 922 #define DEFINE_CAPTURE_GETTER(i) \ | 875 #define DEFINE_CAPTURE_GETTER(i) \ |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 995 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); | 948 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
| 996 const int start_index = match_info->Capture(1); | 949 const int start_index = match_info->Capture(1); |
| 997 Handle<String> last_subject(match_info->LastSubject()); | 950 Handle<String> last_subject(match_info->LastSubject()); |
| 998 const int len = last_subject->length(); | 951 const int len = last_subject->length(); |
| 999 return *isolate->factory()->NewSubString(last_subject, start_index, len); | 952 return *isolate->factory()->NewSubString(last_subject, start_index, len); |
| 1000 } | 953 } |
| 1001 | 954 |
| 1002 namespace { | 955 namespace { |
| 1003 | 956 |
| 1004 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 957 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 1005 compiler::Node* RegExpExec(CodeStubAssembler* a, compiler::Node* context, | 958 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, |
| 1006 compiler::Node* recv, compiler::Node* string) { | 959 Node* string) { |
| 1007 typedef CodeStubAssembler::Variable Variable; | |
| 1008 typedef CodeStubAssembler::Label Label; | |
| 1009 typedef compiler::Node Node; | |
| 1010 | |
| 1011 Isolate* isolate = a->isolate(); | 960 Isolate* isolate = a->isolate(); |
| 1012 | 961 |
| 1013 Node* const null = a->NullConstant(); | 962 Node* const null = a->NullConstant(); |
| 1014 | 963 |
| 1015 Variable var_result(a, MachineRepresentation::kTagged); | 964 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1016 Label out(a), call_builtin_exec(a), slow_path(a, Label::kDeferred); | 965 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); |
| 1017 | 966 |
| 1018 Node* const map = a->LoadMap(recv); | 967 Node* const map = a->LoadMap(recv); |
| 1019 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); | 968 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); |
| 1020 | 969 |
| 1021 a->Bind(&call_builtin_exec); | 970 a->Bind(&call_builtin_exec); |
| 1022 { | 971 { |
| 1023 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); | 972 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); |
| 1024 var_result.Bind(result); | 973 var_result.Bind(result); |
| 1025 a->Goto(&out); | 974 a->Goto(&out); |
| 1026 } | 975 } |
| 1027 | 976 |
| 1028 a->Bind(&slow_path); | 977 a->Bind(&slow_path); |
| 1029 { | 978 { |
| 1030 // Take the slow path of fetching the exec property, calling it, and | 979 // Take the slow path of fetching the exec property, calling it, and |
| 1031 // verifying its return value. | 980 // verifying its return value. |
| 1032 | 981 |
| 1033 // Get the exec property. | 982 // Get the exec property. |
| 1034 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); | 983 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); |
| 1035 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 984 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 1036 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); | 985 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); |
| 1037 | 986 |
| 1038 // Is {exec} callable? | 987 // Is {exec} callable? |
| 1039 Label if_iscallable(a), if_isnotcallable(a); | 988 CLabel if_iscallable(a), if_isnotcallable(a); |
| 1040 | 989 |
| 1041 a->GotoIf(a->TaggedIsSmi(exec), &if_isnotcallable); | 990 a->GotoIf(a->TaggedIsSmi(exec), &if_isnotcallable); |
| 1042 | 991 |
| 1043 Node* const exec_map = a->LoadMap(exec); | 992 Node* const exec_map = a->LoadMap(exec); |
| 1044 a->Branch(a->IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); | 993 a->Branch(a->IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); |
| 1045 | 994 |
| 1046 a->Bind(&if_iscallable); | 995 a->Bind(&if_iscallable); |
| 1047 { | 996 { |
| 1048 Callable call_callable = CodeFactory::Call(isolate); | 997 Callable call_callable = CodeFactory::Call(isolate); |
| 1049 Node* const result = | 998 Node* const result = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1067 } | 1016 } |
| 1068 | 1017 |
| 1069 a->Bind(&out); | 1018 a->Bind(&out); |
| 1070 return var_result.value(); | 1019 return var_result.value(); |
| 1071 } | 1020 } |
| 1072 | 1021 |
| 1073 } // namespace | 1022 } // namespace |
| 1074 | 1023 |
| 1075 // ES#sec-regexp.prototype.test | 1024 // ES#sec-regexp.prototype.test |
| 1076 // RegExp.prototype.test ( S ) | 1025 // RegExp.prototype.test ( S ) |
| 1077 void Builtins::Generate_RegExpPrototypeTest( | 1026 void Builtins::Generate_RegExpPrototypeTest(CodeAssemblerState* state) { |
| 1078 compiler::CodeAssemblerState* state) { | |
| 1079 typedef compiler::Node Node; | |
| 1080 CodeStubAssembler a(state); | 1027 CodeStubAssembler a(state); |
| 1081 | 1028 |
| 1082 Isolate* const isolate = a.isolate(); | 1029 Isolate* const isolate = a.isolate(); |
| 1083 | 1030 |
| 1084 Node* const maybe_receiver = a.Parameter(0); | 1031 Node* const maybe_receiver = a.Parameter(0); |
| 1085 Node* const maybe_string = a.Parameter(1); | 1032 Node* const maybe_string = a.Parameter(1); |
| 1086 Node* const context = a.Parameter(4); | 1033 Node* const context = a.Parameter(4); |
| 1087 | 1034 |
| 1088 // Ensure {maybe_receiver} is a JSReceiver. | 1035 // Ensure {maybe_receiver} is a JSReceiver. |
| 1089 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1036 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1170 } | 1117 } |
| 1171 } | 1118 } |
| 1172 | 1119 |
| 1173 elems->Shrink(n); | 1120 elems->Shrink(n); |
| 1174 return *isolate->factory()->NewJSArrayWithElements(elems); | 1121 return *isolate->factory()->NewJSArrayWithElements(elems); |
| 1175 } | 1122 } |
| 1176 | 1123 |
| 1177 namespace { | 1124 namespace { |
| 1178 | 1125 |
| 1179 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, | 1126 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
| 1180 compiler::Node* const receiver, | 1127 Node* const receiver, |
| 1181 compiler::Node* const string, | 1128 Node* const string, Node* const context, |
| 1182 compiler::Node* const context, | |
| 1183 bool is_fastpath) { | 1129 bool is_fastpath) { |
| 1184 typedef CodeStubAssembler::Label Label; | |
| 1185 typedef compiler::Node Node; | |
| 1186 | |
| 1187 Isolate* const isolate = a->isolate(); | 1130 Isolate* const isolate = a->isolate(); |
| 1188 | 1131 |
| 1189 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1132 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1190 | 1133 |
| 1191 // Grab the initial value of last index. | 1134 // Grab the initial value of last index. |
| 1192 Node* const previous_last_index = | 1135 Node* const previous_last_index = |
| 1193 is_fastpath ? FastLoadLastIndex(a, context, receiver) | 1136 is_fastpath ? FastLoadLastIndex(a, context, receiver) |
| 1194 : SlowLoadLastIndex(a, context, receiver); | 1137 : SlowLoadLastIndex(a, context, receiver); |
| 1195 | 1138 |
| 1196 // Ensure last index is 0. | 1139 // Ensure last index is 0. |
| 1197 if (is_fastpath) { | 1140 if (is_fastpath) { |
| 1198 FastStoreLastIndex(a, context, receiver, smi_zero); | 1141 FastStoreLastIndex(a, context, receiver, smi_zero); |
| 1199 } else { | 1142 } else { |
| 1200 Label next(a); | 1143 CLabel next(a); |
| 1201 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1144 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
| 1202 | 1145 |
| 1203 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1146 SlowStoreLastIndex(a, context, receiver, smi_zero); |
| 1204 a->Goto(&next); | 1147 a->Goto(&next); |
| 1205 a->Bind(&next); | 1148 a->Bind(&next); |
| 1206 } | 1149 } |
| 1207 | 1150 |
| 1208 // Call exec. | 1151 // Call exec. |
| 1209 Node* const match_indices = | 1152 Node* const match_indices = |
| 1210 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) | 1153 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) |
| 1211 : RegExpExec(a, context, receiver, string); | 1154 : RegExpExec(a, context, receiver, string); |
| 1212 | 1155 |
| 1213 // Reset last index if necessary. | 1156 // Reset last index if necessary. |
| 1214 if (is_fastpath) { | 1157 if (is_fastpath) { |
| 1215 FastStoreLastIndex(a, context, receiver, previous_last_index); | 1158 FastStoreLastIndex(a, context, receiver, previous_last_index); |
| 1216 } else { | 1159 } else { |
| 1217 Label next(a); | 1160 CLabel next(a); |
| 1218 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1161 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
| 1219 | 1162 |
| 1220 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1163 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
| 1221 &next); | 1164 &next); |
| 1222 | 1165 |
| 1223 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1166 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
| 1224 a->Goto(&next); | 1167 a->Goto(&next); |
| 1225 a->Bind(&next); | 1168 a->Bind(&next); |
| 1226 } | 1169 } |
| 1227 | 1170 |
| 1228 // Return -1 if no match was found. | 1171 // Return -1 if no match was found. |
| 1229 { | 1172 { |
| 1230 Label next(a); | 1173 CLabel next(a); |
| 1231 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); | 1174 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); |
| 1232 a->Return(a->SmiConstant(-1)); | 1175 a->Return(a->SmiConstant(-1)); |
| 1233 a->Bind(&next); | 1176 a->Bind(&next); |
| 1234 } | 1177 } |
| 1235 | 1178 |
| 1236 // Return the index of the match. | 1179 // Return the index of the match. |
| 1237 { | 1180 { |
| 1238 Label fast_result(a), slow_result(a, Label::kDeferred); | 1181 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); |
| 1239 | 1182 |
| 1240 Node* const native_context = a->LoadNativeContext(context); | 1183 Node* const native_context = a->LoadNativeContext(context); |
| 1241 Node* const initial_regexp_result_map = | 1184 Node* const initial_regexp_result_map = |
| 1242 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 1185 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
| 1243 Node* const match_indices_map = a->LoadMap(match_indices); | 1186 Node* const match_indices_map = a->LoadMap(match_indices); |
| 1244 | 1187 |
| 1245 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), | 1188 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), |
| 1246 &fast_result, &slow_result); | 1189 &fast_result, &slow_result); |
| 1247 | 1190 |
| 1248 a->Bind(&fast_result); | 1191 a->Bind(&fast_result); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1261 a->CallStub(getproperty_callable, context, match_indices, name); | 1204 a->CallStub(getproperty_callable, context, match_indices, name); |
| 1262 a->Return(index); | 1205 a->Return(index); |
| 1263 } | 1206 } |
| 1264 } | 1207 } |
| 1265 } | 1208 } |
| 1266 | 1209 |
| 1267 } // namespace | 1210 } // namespace |
| 1268 | 1211 |
| 1269 // ES#sec-regexp.prototype-@@search | 1212 // ES#sec-regexp.prototype-@@search |
| 1270 // RegExp.prototype [ @@search ] ( string ) | 1213 // RegExp.prototype [ @@search ] ( string ) |
| 1271 void Builtins::Generate_RegExpPrototypeSearch( | 1214 void Builtins::Generate_RegExpPrototypeSearch(CodeAssemblerState* state) { |
| 1272 compiler::CodeAssemblerState* state) { | |
| 1273 typedef CodeStubAssembler::Label Label; | |
| 1274 typedef compiler::Node Node; | |
| 1275 CodeStubAssembler a(state); | 1215 CodeStubAssembler a(state); |
| 1276 | 1216 |
| 1277 Isolate* const isolate = a.isolate(); | 1217 Isolate* const isolate = a.isolate(); |
| 1278 | 1218 |
| 1279 Node* const maybe_receiver = a.Parameter(0); | 1219 Node* const maybe_receiver = a.Parameter(0); |
| 1280 Node* const maybe_string = a.Parameter(1); | 1220 Node* const maybe_string = a.Parameter(1); |
| 1281 Node* const context = a.Parameter(4); | 1221 Node* const context = a.Parameter(4); |
| 1282 | 1222 |
| 1283 // Ensure {maybe_receiver} is a JSReceiver. | 1223 // Ensure {maybe_receiver} is a JSReceiver. |
| 1284 Node* const map = | 1224 Node* const map = |
| 1285 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1225 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, |
| 1286 MessageTemplate::kIncompatibleMethodReceiver, | 1226 MessageTemplate::kIncompatibleMethodReceiver, |
| 1287 "RegExp.prototype.@@search"); | 1227 "RegExp.prototype.@@search"); |
| 1288 Node* const receiver = maybe_receiver; | 1228 Node* const receiver = maybe_receiver; |
| 1289 | 1229 |
| 1290 // Convert {maybe_string} to a String. | 1230 // Convert {maybe_string} to a String. |
| 1291 Node* const string = a.ToString(context, maybe_string); | 1231 Node* const string = a.ToString(context, maybe_string); |
| 1292 | 1232 |
| 1293 Label fast_path(&a), slow_path(&a); | 1233 CLabel fast_path(&a), slow_path(&a); |
| 1294 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); | 1234 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); |
| 1295 | 1235 |
| 1296 a.Bind(&fast_path); | 1236 a.Bind(&fast_path); |
| 1297 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, true); | 1237 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, true); |
| 1298 | 1238 |
| 1299 a.Bind(&slow_path); | 1239 a.Bind(&slow_path); |
| 1300 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, false); | 1240 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, false); |
| 1301 } | 1241 } |
| 1302 | 1242 |
| 1303 namespace { | 1243 namespace { |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1639 Handle<String> substr = | 1579 Handle<String> substr = |
| 1640 factory->NewSubString(string, prev_string_index, length); | 1580 factory->NewSubString(string, prev_string_index, length); |
| 1641 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1581 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
| 1642 } | 1582 } |
| 1643 | 1583 |
| 1644 return *NewJSArrayWithElements(isolate, elems, num_elems); | 1584 return *NewJSArrayWithElements(isolate, elems, num_elems); |
| 1645 } | 1585 } |
| 1646 | 1586 |
| 1647 namespace { | 1587 namespace { |
| 1648 | 1588 |
| 1649 compiler::Node* ReplaceGlobalCallableFastPath( | 1589 Node* ReplaceGlobalCallableFastPath(CodeStubAssembler* a, Node* context, |
| 1650 CodeStubAssembler* a, compiler::Node* context, compiler::Node* regexp, | 1590 Node* regexp, Node* subject_string, |
| 1651 compiler::Node* subject_string, compiler::Node* replace_callable) { | 1591 Node* replace_callable) { |
| 1652 // The fast path is reached only if {receiver} is a global unmodified | 1592 // The fast path is reached only if {receiver} is a global unmodified |
| 1653 // JSRegExp instance and {replace_callable} is callable. | 1593 // JSRegExp instance and {replace_callable} is callable. |
| 1654 | 1594 |
| 1655 typedef CodeStubAssembler::Variable Variable; | |
| 1656 typedef CodeStubAssembler::Label Label; | |
| 1657 typedef compiler::Node Node; | |
| 1658 | |
| 1659 Isolate* const isolate = a->isolate(); | 1595 Isolate* const isolate = a->isolate(); |
| 1660 | 1596 |
| 1661 Node* const null = a->NullConstant(); | 1597 Node* const null = a->NullConstant(); |
| 1662 Node* const undefined = a->UndefinedConstant(); | 1598 Node* const undefined = a->UndefinedConstant(); |
| 1663 Node* const int_zero = a->IntPtrConstant(0); | 1599 Node* const int_zero = a->IntPtrConstant(0); |
| 1664 Node* const int_one = a->IntPtrConstant(1); | 1600 Node* const int_one = a->IntPtrConstant(1); |
| 1665 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1601 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1666 | 1602 |
| 1667 Node* const native_context = a->LoadNativeContext(context); | 1603 Node* const native_context = a->LoadNativeContext(context); |
| 1668 | 1604 |
| 1669 Label out(a); | 1605 CLabel out(a); |
| 1670 Variable var_result(a, MachineRepresentation::kTagged); | 1606 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1671 | 1607 |
| 1672 // Set last index to 0. | 1608 // Set last index to 0. |
| 1673 FastStoreLastIndex(a, context, regexp, smi_zero); | 1609 FastStoreLastIndex(a, context, regexp, smi_zero); |
| 1674 | 1610 |
| 1675 // Allocate {result_array}. | 1611 // Allocate {result_array}. |
| 1676 Node* result_array; | 1612 Node* result_array; |
| 1677 { | 1613 { |
| 1678 ElementsKind kind = FAST_ELEMENTS; | 1614 ElementsKind kind = FAST_ELEMENTS; |
| 1679 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | 1615 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); |
| 1680 Node* const capacity = a->IntPtrConstant(16); | 1616 Node* const capacity = a->IntPtrConstant(16); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1707 | 1643 |
| 1708 Node* const res_length = a->LoadJSArrayLength(res); | 1644 Node* const res_length = a->LoadJSArrayLength(res); |
| 1709 Node* const res_elems = a->LoadElements(res); | 1645 Node* const res_elems = a->LoadElements(res); |
| 1710 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); | 1646 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); |
| 1711 | 1647 |
| 1712 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1648 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
| 1713 Node* const num_capture_registers = a->LoadFixedArrayElement( | 1649 Node* const num_capture_registers = a->LoadFixedArrayElement( |
| 1714 last_match_info, | 1650 last_match_info, |
| 1715 a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, mode); | 1651 a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, mode); |
| 1716 | 1652 |
| 1717 Label if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); | 1653 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); |
| 1718 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), | 1654 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), |
| 1719 &if_noexplicitcaptures, &if_hasexplicitcaptures); | 1655 &if_noexplicitcaptures, &if_hasexplicitcaptures); |
| 1720 | 1656 |
| 1721 a->Bind(&if_noexplicitcaptures); | 1657 a->Bind(&if_noexplicitcaptures); |
| 1722 { | 1658 { |
| 1723 // If the number of captures is two then there are no explicit captures in | 1659 // If the number of captures is two then there are no explicit captures in |
| 1724 // the regexp, just the implicit capture that captures the whole match. In | 1660 // the regexp, just the implicit capture that captures the whole match. In |
| 1725 // this case we can simplify quite a bit and end up with something faster. | 1661 // this case we can simplify quite a bit and end up with something faster. |
| 1726 // The builder will consist of some integers that indicate slices of the | 1662 // The builder will consist of some integers that indicate slices of the |
| 1727 // input string and some replacements that were returned from the replace | 1663 // input string and some replacements that were returned from the replace |
| 1728 // function. | 1664 // function. |
| 1729 | 1665 |
| 1730 Variable var_match_start(a, MachineRepresentation::kTagged); | 1666 CVariable var_match_start(a, MachineRepresentation::kTagged); |
| 1731 var_match_start.Bind(smi_zero); | 1667 var_match_start.Bind(smi_zero); |
| 1732 | 1668 |
| 1733 Node* const end = a->SmiUntag(res_length); | 1669 Node* const end = a->SmiUntag(res_length); |
| 1734 Variable var_i(a, MachineType::PointerRepresentation()); | 1670 CVariable var_i(a, MachineType::PointerRepresentation()); |
| 1735 var_i.Bind(int_zero); | 1671 var_i.Bind(int_zero); |
| 1736 | 1672 |
| 1737 Variable* vars[] = {&var_i, &var_match_start}; | 1673 CVariable* vars[] = {&var_i, &var_match_start}; |
| 1738 Label loop(a, 2, vars); | 1674 CLabel loop(a, 2, vars); |
| 1739 a->Goto(&loop); | 1675 a->Goto(&loop); |
| 1740 a->Bind(&loop); | 1676 a->Bind(&loop); |
| 1741 { | 1677 { |
| 1742 Node* const i = var_i.value(); | 1678 Node* const i = var_i.value(); |
| 1743 a->GotoUnless(a->IntPtrLessThan(i, end), &create_result); | 1679 a->GotoUnless(a->IntPtrLessThan(i, end), &create_result); |
| 1744 | 1680 |
| 1745 CodeStubAssembler::ParameterMode mode = | 1681 CodeStubAssembler::ParameterMode mode = |
| 1746 CodeStubAssembler::INTPTR_PARAMETERS; | 1682 CodeStubAssembler::INTPTR_PARAMETERS; |
| 1747 Node* const elem = a->LoadFixedArrayElement(res_elems, i, 0, mode); | 1683 Node* const elem = a->LoadFixedArrayElement(res_elems, i, 0, mode); |
| 1748 | 1684 |
| 1749 Label if_issmi(a), if_isstring(a), loop_epilogue(a); | 1685 CLabel if_issmi(a), if_isstring(a), loop_epilogue(a); |
| 1750 a->Branch(a->TaggedIsSmi(elem), &if_issmi, &if_isstring); | 1686 a->Branch(a->TaggedIsSmi(elem), &if_issmi, &if_isstring); |
| 1751 | 1687 |
| 1752 a->Bind(&if_issmi); | 1688 a->Bind(&if_issmi); |
| 1753 { | 1689 { |
| 1754 // Integers represent slices of the original string. | 1690 // Integers represent slices of the original string. |
| 1755 Label if_isnegativeorzero(a), if_ispositive(a); | 1691 CLabel if_isnegativeorzero(a), if_ispositive(a); |
| 1756 a->BranchIfSmiLessThanOrEqual(elem, smi_zero, &if_isnegativeorzero, | 1692 a->BranchIfSmiLessThanOrEqual(elem, smi_zero, &if_isnegativeorzero, |
| 1757 &if_ispositive); | 1693 &if_ispositive); |
| 1758 | 1694 |
| 1759 a->Bind(&if_ispositive); | 1695 a->Bind(&if_ispositive); |
| 1760 { | 1696 { |
| 1761 Node* const int_elem = a->SmiUntag(elem); | 1697 Node* const int_elem = a->SmiUntag(elem); |
| 1762 Node* const new_match_start = | 1698 Node* const new_match_start = |
| 1763 a->IntPtrAdd(a->WordShr(int_elem, a->IntPtrConstant(11)), | 1699 a->IntPtrAdd(a->WordShr(int_elem, a->IntPtrConstant(11)), |
| 1764 a->WordAnd(int_elem, a->IntPtrConstant(0x7ff))); | 1700 a->WordAnd(int_elem, a->IntPtrConstant(0x7ff))); |
| 1765 var_match_start.Bind(a->SmiTag(new_match_start)); | 1701 var_match_start.Bind(a->SmiTag(new_match_start)); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1817 Node* const to = a->SmiUntag(res_length); | 1753 Node* const to = a->SmiUntag(res_length); |
| 1818 const int increment = 1; | 1754 const int increment = 1; |
| 1819 | 1755 |
| 1820 a->BuildFastLoop( | 1756 a->BuildFastLoop( |
| 1821 MachineType::PointerRepresentation(), from, to, | 1757 MachineType::PointerRepresentation(), from, to, |
| 1822 [res_elems, isolate, native_context, context, undefined, | 1758 [res_elems, isolate, native_context, context, undefined, |
| 1823 replace_callable, mode](CodeStubAssembler* a, Node* index) { | 1759 replace_callable, mode](CodeStubAssembler* a, Node* index) { |
| 1824 Node* const elem = | 1760 Node* const elem = |
| 1825 a->LoadFixedArrayElement(res_elems, index, 0, mode); | 1761 a->LoadFixedArrayElement(res_elems, index, 0, mode); |
| 1826 | 1762 |
| 1827 Label do_continue(a); | 1763 CLabel do_continue(a); |
| 1828 a->GotoIf(a->TaggedIsSmi(elem), &do_continue); | 1764 a->GotoIf(a->TaggedIsSmi(elem), &do_continue); |
| 1829 | 1765 |
| 1830 // elem must be an Array. | 1766 // elem must be an Array. |
| 1831 // Use the apply argument as backing for global RegExp properties. | 1767 // Use the apply argument as backing for global RegExp properties. |
| 1832 | 1768 |
| 1833 CSA_ASSERT(a, a->HasInstanceType(elem, JS_ARRAY_TYPE)); | 1769 CSA_ASSERT(a, a->HasInstanceType(elem, JS_ARRAY_TYPE)); |
| 1834 | 1770 |
| 1835 // TODO(jgruber): Remove indirection through Call->ReflectApply. | 1771 // TODO(jgruber): Remove indirection through Call->ReflectApply. |
| 1836 Callable call_callable = CodeFactory::Call(isolate); | 1772 Callable call_callable = CodeFactory::Call(isolate); |
| 1837 Node* const reflect_apply = a->LoadContextElement( | 1773 Node* const reflect_apply = a->LoadContextElement( |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1861 Node* const result = a->CallRuntime(Runtime::kStringBuilderConcat, context, | 1797 Node* const result = a->CallRuntime(Runtime::kStringBuilderConcat, context, |
| 1862 res, res_length, subject_string); | 1798 res, res_length, subject_string); |
| 1863 var_result.Bind(result); | 1799 var_result.Bind(result); |
| 1864 a->Goto(&out); | 1800 a->Goto(&out); |
| 1865 } | 1801 } |
| 1866 | 1802 |
| 1867 a->Bind(&out); | 1803 a->Bind(&out); |
| 1868 return var_result.value(); | 1804 return var_result.value(); |
| 1869 } | 1805 } |
| 1870 | 1806 |
| 1871 compiler::Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, | 1807 Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, Node* context, |
| 1872 compiler::Node* context, | 1808 Node* regexp, Node* subject_string, |
| 1873 compiler::Node* regexp, | 1809 Node* replace_string) { |
| 1874 compiler::Node* subject_string, | |
| 1875 compiler::Node* replace_string) { | |
| 1876 // The fast path is reached only if {receiver} is an unmodified | 1810 // The fast path is reached only if {receiver} is an unmodified |
| 1877 // JSRegExp instance, {replace_value} is non-callable, and | 1811 // JSRegExp instance, {replace_value} is non-callable, and |
| 1878 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple | 1812 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple |
| 1879 // string replacement. | 1813 // string replacement. |
| 1880 | 1814 |
| 1881 typedef CodeStubAssembler::Variable Variable; | |
| 1882 typedef CodeStubAssembler::Label Label; | |
| 1883 typedef compiler::Node Node; | |
| 1884 | |
| 1885 Isolate* const isolate = a->isolate(); | 1815 Isolate* const isolate = a->isolate(); |
| 1886 | 1816 |
| 1887 Node* const null = a->NullConstant(); | 1817 Node* const null = a->NullConstant(); |
| 1888 Node* const int_zero = a->IntPtrConstant(0); | 1818 Node* const int_zero = a->IntPtrConstant(0); |
| 1889 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1819 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 1890 | 1820 |
| 1891 Label out(a); | 1821 CLabel out(a); |
| 1892 Variable var_result(a, MachineRepresentation::kTagged); | 1822 CVariable var_result(a, MachineRepresentation::kTagged); |
| 1893 | 1823 |
| 1894 // Load the last match info. | 1824 // Load the last match info. |
| 1895 Node* const native_context = a->LoadNativeContext(context); | 1825 Node* const native_context = a->LoadNativeContext(context); |
| 1896 Node* const last_match_info = a->LoadContextElement( | 1826 Node* const last_match_info = a->LoadContextElement( |
| 1897 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1827 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 1898 | 1828 |
| 1899 // Is {regexp} global? | 1829 // Is {regexp} global? |
| 1900 Label if_isglobal(a), if_isnonglobal(a); | 1830 CLabel if_isglobal(a), if_isnonglobal(a); |
| 1901 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 1831 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 1902 Node* const is_global = | 1832 Node* const is_global = |
| 1903 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); | 1833 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); |
| 1904 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); | 1834 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); |
| 1905 | 1835 |
| 1906 a->Bind(&if_isglobal); | 1836 a->Bind(&if_isglobal); |
| 1907 { | 1837 { |
| 1908 // Hand off global regexps to runtime. | 1838 // Hand off global regexps to runtime. |
| 1909 FastStoreLastIndex(a, context, regexp, smi_zero); | 1839 FastStoreLastIndex(a, context, regexp, smi_zero); |
| 1910 Node* const result = | 1840 Node* const result = |
| 1911 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, | 1841 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, |
| 1912 subject_string, regexp, replace_string, last_match_info); | 1842 subject_string, regexp, replace_string, last_match_info); |
| 1913 var_result.Bind(result); | 1843 var_result.Bind(result); |
| 1914 a->Goto(&out); | 1844 a->Goto(&out); |
| 1915 } | 1845 } |
| 1916 | 1846 |
| 1917 a->Bind(&if_isnonglobal); | 1847 a->Bind(&if_isnonglobal); |
| 1918 { | 1848 { |
| 1919 // Run exec, then manually construct the resulting string. | 1849 // Run exec, then manually construct the resulting string. |
| 1920 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 1850 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 1921 Node* const match_indices = | 1851 Node* const match_indices = |
| 1922 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, | 1852 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, |
| 1923 last_match_info); | 1853 last_match_info); |
| 1924 | 1854 |
| 1925 Label if_matched(a), if_didnotmatch(a); | 1855 CLabel if_matched(a), if_didnotmatch(a); |
| 1926 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 1856 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
| 1927 | 1857 |
| 1928 a->Bind(&if_didnotmatch); | 1858 a->Bind(&if_didnotmatch); |
| 1929 { | 1859 { |
| 1930 FastStoreLastIndex(a, context, regexp, smi_zero); | 1860 FastStoreLastIndex(a, context, regexp, smi_zero); |
| 1931 var_result.Bind(subject_string); | 1861 var_result.Bind(subject_string); |
| 1932 a->Goto(&out); | 1862 a->Goto(&out); |
| 1933 } | 1863 } |
| 1934 | 1864 |
| 1935 a->Bind(&if_matched); | 1865 a->Bind(&if_matched); |
| 1936 { | 1866 { |
| 1937 CodeStubAssembler::ParameterMode mode = | 1867 CodeStubAssembler::ParameterMode mode = |
| 1938 CodeStubAssembler::INTPTR_PARAMETERS; | 1868 CodeStubAssembler::INTPTR_PARAMETERS; |
| 1939 | 1869 |
| 1940 Node* const subject_start = smi_zero; | 1870 Node* const subject_start = smi_zero; |
| 1941 Node* const match_start = a->LoadFixedArrayElement( | 1871 Node* const match_start = a->LoadFixedArrayElement( |
| 1942 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), | 1872 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), |
| 1943 0, mode); | 1873 0, mode); |
| 1944 Node* const match_end = a->LoadFixedArrayElement( | 1874 Node* const match_end = a->LoadFixedArrayElement( |
| 1945 match_indices, | 1875 match_indices, |
| 1946 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); | 1876 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); |
| 1947 Node* const subject_end = a->LoadStringLength(subject_string); | 1877 Node* const subject_end = a->LoadStringLength(subject_string); |
| 1948 | 1878 |
| 1949 Label if_replaceisempty(a), if_replaceisnotempty(a); | 1879 CLabel if_replaceisempty(a), if_replaceisnotempty(a); |
| 1950 Node* const replace_length = a->LoadStringLength(replace_string); | 1880 Node* const replace_length = a->LoadStringLength(replace_string); |
| 1951 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, | 1881 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, |
| 1952 &if_replaceisnotempty); | 1882 &if_replaceisnotempty); |
| 1953 | 1883 |
| 1954 a->Bind(&if_replaceisempty); | 1884 a->Bind(&if_replaceisempty); |
| 1955 { | 1885 { |
| 1956 // TODO(jgruber): We could skip many of the checks that using SubString | 1886 // TODO(jgruber): We could skip many of the checks that using SubString |
| 1957 // here entails. | 1887 // here entails. |
| 1958 | 1888 |
| 1959 Node* const first_part = | 1889 Node* const first_part = |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1984 } | 1914 } |
| 1985 | 1915 |
| 1986 a->Bind(&out); | 1916 a->Bind(&out); |
| 1987 return var_result.value(); | 1917 return var_result.value(); |
| 1988 } | 1918 } |
| 1989 | 1919 |
| 1990 } // namespace | 1920 } // namespace |
| 1991 | 1921 |
| 1992 // ES#sec-regexp.prototype-@@replace | 1922 // ES#sec-regexp.prototype-@@replace |
| 1993 // RegExp.prototype [ @@replace ] ( string, replaceValue ) | 1923 // RegExp.prototype [ @@replace ] ( string, replaceValue ) |
| 1994 void Builtins::Generate_RegExpPrototypeReplace( | 1924 void Builtins::Generate_RegExpPrototypeReplace(CodeAssemblerState* state) { |
| 1995 compiler::CodeAssemblerState* state) { | |
| 1996 typedef CodeStubAssembler::Label Label; | |
| 1997 typedef compiler::Node Node; | |
| 1998 CodeStubAssembler a(state); | 1925 CodeStubAssembler a(state); |
| 1999 | 1926 |
| 2000 Isolate* const isolate = a.isolate(); | 1927 Isolate* const isolate = a.isolate(); |
| 2001 | 1928 |
| 2002 Node* const maybe_receiver = a.Parameter(0); | 1929 Node* const maybe_receiver = a.Parameter(0); |
| 2003 Node* const maybe_string = a.Parameter(1); | 1930 Node* const maybe_string = a.Parameter(1); |
| 2004 Node* const replace_value = a.Parameter(2); | 1931 Node* const replace_value = a.Parameter(2); |
| 2005 Node* const context = a.Parameter(5); | 1932 Node* const context = a.Parameter(5); |
| 2006 | 1933 |
| 2007 Node* const int_zero = a.IntPtrConstant(0); | 1934 Node* const int_zero = a.IntPtrConstant(0); |
| 2008 | 1935 |
| 2009 // Ensure {maybe_receiver} is a JSReceiver. | 1936 // Ensure {maybe_receiver} is a JSReceiver. |
| 2010 Node* const map = | 1937 Node* const map = |
| 2011 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1938 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, |
| 2012 MessageTemplate::kIncompatibleMethodReceiver, | 1939 MessageTemplate::kIncompatibleMethodReceiver, |
| 2013 "RegExp.prototype.@@replace"); | 1940 "RegExp.prototype.@@replace"); |
| 2014 Node* const receiver = maybe_receiver; | 1941 Node* const receiver = maybe_receiver; |
| 2015 | 1942 |
| 2016 // Convert {maybe_string} to a String. | 1943 // Convert {maybe_string} to a String. |
| 2017 Callable tostring_callable = CodeFactory::ToString(isolate); | 1944 Callable tostring_callable = CodeFactory::ToString(isolate); |
| 2018 Node* const string = a.CallStub(tostring_callable, context, maybe_string); | 1945 Node* const string = a.CallStub(tostring_callable, context, maybe_string); |
| 2019 | 1946 |
| 2020 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 1947 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
| 2021 Label checkreplacecallable(&a), runtime(&a, Label::kDeferred), fastpath(&a); | 1948 CLabel checkreplacecallable(&a), runtime(&a, CLabel::kDeferred), fastpath(&a); |
| 2022 BranchIfFastPath(&a, context, map, &checkreplacecallable, &runtime); | 1949 BranchIfFastPath(&a, context, map, &checkreplacecallable, &runtime); |
| 2023 | 1950 |
| 2024 a.Bind(&checkreplacecallable); | 1951 a.Bind(&checkreplacecallable); |
| 2025 Node* const regexp = receiver; | 1952 Node* const regexp = receiver; |
| 2026 | 1953 |
| 2027 // 2. Is {replace_value} callable? | 1954 // 2. Is {replace_value} callable? |
| 2028 Label checkreplacestring(&a), if_iscallable(&a); | 1955 CLabel checkreplacestring(&a), if_iscallable(&a); |
| 2029 a.GotoIf(a.TaggedIsSmi(replace_value), &checkreplacestring); | 1956 a.GotoIf(a.TaggedIsSmi(replace_value), &checkreplacestring); |
| 2030 | 1957 |
| 2031 Node* const replace_value_map = a.LoadMap(replace_value); | 1958 Node* const replace_value_map = a.LoadMap(replace_value); |
| 2032 a.Branch(a.IsCallableMap(replace_value_map), &if_iscallable, | 1959 a.Branch(a.IsCallableMap(replace_value_map), &if_iscallable, |
| 2033 &checkreplacestring); | 1960 &checkreplacestring); |
| 2034 | 1961 |
| 2035 // 3. Does ToString({replace_value}) contain '$'? | 1962 // 3. Does ToString({replace_value}) contain '$'? |
| 2036 a.Bind(&checkreplacestring); | 1963 a.Bind(&checkreplacestring); |
| 2037 { | 1964 { |
| 2038 Node* const replace_string = | 1965 Node* const replace_string = |
| 2039 a.CallStub(tostring_callable, context, replace_value); | 1966 a.CallStub(tostring_callable, context, replace_value); |
| 2040 | 1967 |
| 2041 Node* const dollar_char = a.IntPtrConstant('$'); | 1968 Node* const dollar_char = a.IntPtrConstant('$'); |
| 2042 Node* const smi_minusone = a.SmiConstant(Smi::FromInt(-1)); | 1969 Node* const smi_minusone = a.SmiConstant(Smi::FromInt(-1)); |
| 2043 a.GotoUnless(a.SmiEqual(a.StringIndexOfChar(context, replace_string, | 1970 a.GotoUnless(a.SmiEqual(a.StringIndexOfChar(context, replace_string, |
| 2044 dollar_char, int_zero), | 1971 dollar_char, int_zero), |
| 2045 smi_minusone), | 1972 smi_minusone), |
| 2046 &runtime); | 1973 &runtime); |
| 2047 | 1974 |
| 2048 a.Return(ReplaceSimpleStringFastPath(&a, context, regexp, string, | 1975 a.Return(ReplaceSimpleStringFastPath(&a, context, regexp, string, |
| 2049 replace_string)); | 1976 replace_string)); |
| 2050 } | 1977 } |
| 2051 | 1978 |
| 2052 // {regexp} is unmodified and {replace_value} is callable. | 1979 // {regexp} is unmodified and {replace_value} is callable. |
| 2053 a.Bind(&if_iscallable); | 1980 a.Bind(&if_iscallable); |
| 2054 { | 1981 { |
| 2055 Node* const replace_callable = replace_value; | 1982 Node* const replace_callable = replace_value; |
| 2056 | 1983 |
| 2057 // Check if the {regexp} is global. | 1984 // Check if the {regexp} is global. |
| 2058 Label if_isglobal(&a), if_isnotglobal(&a); | 1985 CLabel if_isglobal(&a), if_isnotglobal(&a); |
| 2059 Node* const is_global = FastFlagGetter(&a, regexp, JSRegExp::kGlobal); | 1986 Node* const is_global = FastFlagGetter(&a, regexp, JSRegExp::kGlobal); |
| 2060 a.Branch(is_global, &if_isglobal, &if_isnotglobal); | 1987 a.Branch(is_global, &if_isglobal, &if_isnotglobal); |
| 2061 | 1988 |
| 2062 a.Bind(&if_isglobal); | 1989 a.Bind(&if_isglobal); |
| 2063 { | 1990 { |
| 2064 Node* const result = ReplaceGlobalCallableFastPath( | 1991 Node* const result = ReplaceGlobalCallableFastPath( |
| 2065 &a, context, regexp, string, replace_callable); | 1992 &a, context, regexp, string, replace_callable); |
| 2066 a.Return(result); | 1993 a.Return(result); |
| 2067 } | 1994 } |
| 2068 | 1995 |
| 2069 a.Bind(&if_isnotglobal); | 1996 a.Bind(&if_isnotglobal); |
| 2070 { | 1997 { |
| 2071 Node* const result = | 1998 Node* const result = |
| 2072 a.CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction, | 1999 a.CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction, |
| 2073 context, string, regexp, replace_callable); | 2000 context, string, regexp, replace_callable); |
| 2074 a.Return(result); | 2001 a.Return(result); |
| 2075 } | 2002 } |
| 2076 } | 2003 } |
| 2077 | 2004 |
| 2078 a.Bind(&runtime); | 2005 a.Bind(&runtime); |
| 2079 { | 2006 { |
| 2080 Node* const result = a.CallRuntime(Runtime::kRegExpReplace, context, | 2007 Node* const result = a.CallRuntime(Runtime::kRegExpReplace, context, |
| 2081 receiver, string, replace_value); | 2008 receiver, string, replace_value); |
| 2082 a.Return(result); | 2009 a.Return(result); |
| 2083 } | 2010 } |
| 2084 } | 2011 } |
| 2085 | 2012 |
| 2086 // Simple string matching functionality for internal use which does not modify | 2013 // Simple string matching functionality for internal use which does not modify |
| 2087 // the last match info. | 2014 // the last match info. |
| 2088 void Builtins::Generate_RegExpInternalMatch( | 2015 void Builtins::Generate_RegExpInternalMatch(CodeAssemblerState* state) { |
| 2089 compiler::CodeAssemblerState* state) { | |
| 2090 typedef CodeStubAssembler::Label Label; | |
| 2091 typedef compiler::Node Node; | |
| 2092 CodeStubAssembler a(state); | 2016 CodeStubAssembler a(state); |
| 2093 | 2017 |
| 2094 Isolate* const isolate = a.isolate(); | 2018 Isolate* const isolate = a.isolate(); |
| 2095 | 2019 |
| 2096 Node* const regexp = a.Parameter(1); | 2020 Node* const regexp = a.Parameter(1); |
| 2097 Node* const string = a.Parameter(2); | 2021 Node* const string = a.Parameter(2); |
| 2098 Node* const context = a.Parameter(5); | 2022 Node* const context = a.Parameter(5); |
| 2099 | 2023 |
| 2100 Node* const null = a.NullConstant(); | 2024 Node* const null = a.NullConstant(); |
| 2101 Node* const smi_zero = a.SmiConstant(Smi::FromInt(0)); | 2025 Node* const smi_zero = a.SmiConstant(Smi::FromInt(0)); |
| 2102 | 2026 |
| 2103 Node* const native_context = a.LoadNativeContext(context); | 2027 Node* const native_context = a.LoadNativeContext(context); |
| 2104 Node* const internal_match_info = a.LoadContextElement( | 2028 Node* const internal_match_info = a.LoadContextElement( |
| 2105 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); | 2029 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); |
| 2106 | 2030 |
| 2107 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2031 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
| 2108 Node* const match_indices = a.CallStub(exec_callable, context, regexp, string, | 2032 Node* const match_indices = a.CallStub(exec_callable, context, regexp, string, |
| 2109 smi_zero, internal_match_info); | 2033 smi_zero, internal_match_info); |
| 2110 | 2034 |
| 2111 Label if_matched(&a), if_didnotmatch(&a); | 2035 CLabel if_matched(&a), if_didnotmatch(&a); |
| 2112 a.Branch(a.WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2036 a.Branch(a.WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
| 2113 | 2037 |
| 2114 a.Bind(&if_didnotmatch); | 2038 a.Bind(&if_didnotmatch); |
| 2115 a.Return(null); | 2039 a.Return(null); |
| 2116 | 2040 |
| 2117 a.Bind(&if_matched); | 2041 a.Bind(&if_matched); |
| 2118 { | 2042 { |
| 2119 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2043 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
| 2120 match_indices, string); | 2044 match_indices, string); |
| 2121 a.Return(result); | 2045 a.Return(result); |
| 2122 } | 2046 } |
| 2123 } | 2047 } |
| 2124 | 2048 |
| 2125 } // namespace internal | 2049 } // namespace internal |
| 2126 } // namespace v8 | 2050 } // namespace v8 |
| OLD | NEW |