341 case GetGlobalObject: {
342 if (JSObject* object = m_node->child1()->dynamicCastConstant<JSObject*>()) {
343 m_graph.convertToConstant(m_node, object->globalObject());
344 m_changed = true;
345 break;
346 }
347 break;
348 }
349
350 case RegExpExec:
351 case RegExpTest: {
352 dataLog("Here!\n");
353 JSGlobalObject* globalObject = m_node->child1()->dynamicCastConstant<JSGlobalObject*>();
354 if (!globalObject)
355 break;
356
357 dataLog("Here.\n");
358
359 if (globalObject->isHavingABadTime())
360 break;
361
362 dataLog("Getting regexp!\n");
363
364 Node* regExpObjectNode = m_node->child2().node();
365 RegExp* regExp;
366 if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>())
367 regExp = regExpObject->regExp();
368 else if (regExpObjectNode->op() == NewRegexp)
369 regExp = codeBlock()->regexp(regExpObjectNode->regexpIndex());
370 else
371 break;
372
373 Node* stringNode = m_node->child3().node();
374
375 dataLog("Still here!\n");
376
377 // NOTE: This mostly already protects us from having the compiler execute a regexp
378 // operation on a ginormous string by preventing us from getting our hands on ginormous
379 // strings in the first place.
380 String string = m_node->child3()->tryGetString(m_graph);
381 if (!string)
382 break;
383
384 FrozenValue* regExpFrozenValue = m_graph.freeze(regExp);
385
386 // Refuse to do things with regular expressions that have a ginormous number of
387 // subpatterns.
388 unsigned ginormousNumberOfSubPatterns = 1000;
389 if (regExp->numSubpatterns() > ginormousNumberOfSubPatterns)
390 break;
391
392 dataLog("And still here!\n");
393
394 unsigned lastIndex;
395 if (regExp->globalOrSticky()) {
396 // This will only work if we can prove what the value of lastIndex is. To do this
397 // safely, we need to execute the insertion set so that we see any previous strength
398 // reductions. This is needed for soundness since otherwise the effectfulness of any
399 // previous strength reductions would be invisible to us.
400 executeInsertionSet();
401 lastIndex = UINT_MAX;
402 for (unsigned otherNodeIndex = m_nodeIndex; otherNodeIndex--;) {
403 Node* otherNode = m_block->at(otherNodeIndex);
404 if (otherNode == regExpObjectNode) {
405 lastIndex = 0;
406 break;
407 }
408 if (otherNode->op() == SetRegExpObjectLastIndex
409 && otherNode->child1() == regExpObjectNode
410 && otherNode->child2()->isInt32Constant()
411 && otherNode->child2()->asInt32() >= 0) {
412 lastIndex = static_cast<unsigned>(otherNode->child2()->asInt32());
413 break;
414 }
415 if (writesOverlap(m_graph, otherNode, RegExpObject_lastIndex))
416 break;
417 }
418 if (lastIndex == UINT_MAX)
419 break;
420 } else
421 lastIndex = 0;
422
423 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
424
425 Structure* structure = globalObject->regExpMatchesArrayStructure();
426 if (structure->indexingType() != ArrayWithContiguous) {
427 // This is further protection against a race with haveABadTime.
428 break;
429 }
430 m_graph.registerStructure(structure);
431
432 RegExpConstructor* constructor = globalObject->regExpConstructor();
433 FrozenValue* constructorFrozenValue = m_graph.freeze(constructor);
434
435 int position;
436 Vector<int, 32> ovector;
437 if (!regExp->matchConcurrently(vm(), string, lastIndex, position, ovector))
438 break;
439
440 // We've constant-folded the regexp. Now we're committed to replacing RegExpExec/Test.
441
442 m_changed = true;
443
444 NodeOrigin origin = m_node->origin;
445
446 m_insertionSet.insertNode(
447 m_nodeIndex, SpecNone, Check, origin, m_node->children.justChecks());
448
449 if (m_node->op() == RegExpExec) {
450 StructureSet* structureSet = m_graph.addStructureSet(structure);
451
452 // Create an array modeling the JS array that we will try to allocate. This is
453 // basically createRegExpMatchesArray but over C++ strings instead of JSStrings.
454 Vector<String> resultArray;
455 resultArray.append(string.substring(position, ovector[1]));
456 for (unsigned i = 1; i <= regExp->numSubpatterns(); ++i) {
457 int start = ovector[2 * i];
458 if (start >= 0)
459 resultArray.append(string.substring(start, ovector[2 * i + 1] - start));
460 else
461 resultArray.append(String());
462 }
463
464 unsigned publicLength = resultArray.size();
465 unsigned vectorLength = std::max(BASE_VECTOR_LEN, publicLength);
466
467 UniquedStringImpl* indexUID = vm().propertyNames->index.impl();
468 UniquedStringImpl* inputUID = vm().propertyNames->input.impl();
469 unsigned indexIndex = m_graph.identifiers().ensure(indexUID);
470 unsigned inputIndex = m_graph.identifiers().ensure(inputUID);
471
472 unsigned firstChild = m_graph.m_varArgChildren.size();
473 m_graph.m_varArgChildren.append(
474 m_insertionSet.insertConstantForUse(
475 m_nodeIndex, origin, structure, KnownCellUse));
476 ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add();
477
478 m_graph.m_varArgChildren.append(
479 m_insertionSet.insertConstantForUse(
480 m_nodeIndex, origin, jsNumber(publicLength), KnownInt32Use));
481 data->m_properties.append(PublicLengthPLoc);
482
483 m_graph.m_varArgChildren.append(
484 m_insertionSet.insertConstantForUse(
485 m_nodeIndex, origin, jsNumber(vectorLength), KnownInt32Use));
486 data->m_properties.append(VectorLengthPLoc);
487
488 m_graph.m_varArgChildren.append(
489 m_insertionSet.insertConstantForUse(
490 m_nodeIndex, origin, jsNumber(position), UntypedUse));
491 data->m_properties.append(
492 PromotedLocationDescriptor(NamedPropertyPLoc, indexIndex));
493
494 m_graph.m_varArgChildren.append(Edge(stringNode, UntypedUse));
495 data->m_properties.append(
496 PromotedLocationDescriptor(NamedPropertyPLoc, inputIndex));
497
498 auto materializeString = [&] (const String& string) -> Node* {
499 if (string.isNull())
500 return nullptr;
501 if (string.isEmpty()) {
502 return m_insertionSet.insertConstant(
503 m_nodeIndex, origin, vm().smallStrings.emptyString());
504 }
505 return m_insertionSet.insertNode(
506 m_nodeIndex, SpecNone, LazyJSConstant, origin,
507 OpInfo(m_graph.m_lazyJSValues.add(LazyJSValue::newString(m_graph, string))));
508 };
509
510 for (unsigned i = 0; i < resultArray.size(); ++i) {
511 if (Node* node = materializeString(resultArray[i])) {
512 m_graph.m_varArgChildren.append(Edge(node, UntypedUse));
513 data->m_properties.append(
514 PromotedLocationDescriptor(IndexedPropertyPLoc, i));
515 }
516 }
517
518 Node* resultNode = m_insertionSet.insertNode(
519 m_nodeIndex, SpecArray, Node::VarArg, MaterializeNewObject, origin,
520 OpInfo(structureSet), OpInfo(data), firstChild,
521 m_graph.m_varArgChildren.size() - firstChild);
522
523 m_node->convertToIdentityOn(resultNode);
524 } else
525 m_graph.convertToConstant(m_node, jsBoolean(position != -1));
526
527 // Whether it's Exec or Test, we need to tell the constructor and RegExpObject what's up.
528 if (position != -1) {
529 unsigned firstChild = m_graph.m_varArgChildren.size();
530 m_graph.m_varArgChildren.append(
531 m_insertionSet.insertConstantForUse(
532 m_nodeIndex, origin, constructorFrozenValue, KnownCellUse));
533 m_graph.m_varArgChildren.append(
534 m_insertionSet.insertConstantForUse(
535 m_nodeIndex, origin, regExpFrozenValue, KnownCellUse));
536 m_graph.m_varArgChildren.append(Edge(stringNode, KnownCellUse));
537 m_graph.m_varArgChildren.append(
538 m_insertionSet.insertConstantForUse(
539 m_nodeIndex, origin, jsNumber(position), KnownInt32Use));
540 m_graph.m_varArgChildren.append(
541 m_insertionSet.insertConstantForUse(
542 m_nodeIndex, origin, jsNumber(ovector[1]), KnownInt32Use));
543 m_insertionSet.insertNode(
544 m_nodeIndex, SpecNone, Node::VarArg, RecordRegExpCachedResult, origin,
545 OpInfo(), OpInfo(), firstChild, m_graph.m_varArgChildren.size() - firstChild);
546
547 origin = origin.withInvalidExit();
548 }
549
550 if (regExp->globalOrSticky()) {
551 m_insertionSet.insertNode(
552 m_nodeIndex, SpecNone, SetRegExpObjectLastIndex, origin,
553 Edge(regExpObjectNode, RegExpObjectUse),
554 m_insertionSet.insertConstantForUse(
555 m_nodeIndex, m_node->origin,
556 jsNumber(position == -1 ? 0 : ovector[1]), UntypedUse));
557
558 origin = origin.withInvalidExit();
559 }
560
561 m_node->origin = origin;
562 break;
563 }
564