LCOV - code coverage report
Current view: top level - src/regexp - regexp-utils.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 60 66 90.9 %
Date: 2019-04-17 Functions: 9 9 100.0 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/regexp/regexp-utils.h"
       6             : 
       7             : #include "src/heap/factory.h"
       8             : #include "src/isolate.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/objects/js-regexp-inl.h"
      11             : #include "src/regexp/jsregexp.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16      251509 : Handle<String> RegExpUtils::GenericCaptureGetter(
      17             :     Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture,
      18             :     bool* ok) {
      19      251509 :   const int index = capture * 2;
      20      251509 :   if (index >= match_info->NumberOfCaptureRegisters()) {
      21        1849 :     if (ok != nullptr) *ok = false;
      22             :     return isolate->factory()->empty_string();
      23             :   }
      24             : 
      25             :   const int match_start = match_info->Capture(index);
      26             :   const int match_end = match_info->Capture(index + 1);
      27      249660 :   if (match_start == -1 || match_end == -1) {
      28         207 :     if (ok != nullptr) *ok = false;
      29             :     return isolate->factory()->empty_string();
      30             :   }
      31             : 
      32      249453 :   if (ok != nullptr) *ok = true;
      33             :   Handle<String> last_subject(match_info->LastSubject(), isolate);
      34      249453 :   return isolate->factory()->NewSubString(last_subject, match_start, match_end);
      35             : }
      36             : 
      37             : namespace {
      38             : 
      39             : V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, JSReceiver recv) {
      40       20632 :   return recv->map() == isolate->regexp_function()->initial_map();
      41             : }
      42             : 
      43             : }  // namespace
      44             : 
      45        3651 : MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate,
      46             :                                               Handle<JSReceiver> recv,
      47             :                                               uint64_t value) {
      48             :   Handle<Object> value_as_object =
      49        3651 :       isolate->factory()->NewNumberFromInt64(value);
      50        3651 :   if (HasInitialRegExpMap(isolate, *recv)) {
      51             :     JSRegExp::cast(*recv)->set_last_index(*value_as_object, SKIP_WRITE_BARRIER);
      52        3237 :     return recv;
      53             :   } else {
      54             :     return Object::SetProperty(
      55             :         isolate, recv, isolate->factory()->lastIndex_string(), value_as_object,
      56         414 :         StoreOrigin::kMaybeKeyed, Just(kThrowOnError));
      57             :   }
      58             : }
      59             : 
      60         476 : MaybeHandle<Object> RegExpUtils::GetLastIndex(Isolate* isolate,
      61             :                                               Handle<JSReceiver> recv) {
      62         476 :   if (HasInitialRegExpMap(isolate, *recv)) {
      63         458 :     return handle(JSRegExp::cast(*recv)->last_index(), isolate);
      64             :   } else {
      65             :     return Object::GetProperty(isolate, recv,
      66          18 :                                isolate->factory()->lastIndex_string());
      67             :   }
      68             : }
      69             : 
      70             : // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
      71             : // Also takes an optional exec method in case our caller
      72             : // has already fetched exec.
      73        1878 : MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate,
      74             :                                             Handle<JSReceiver> regexp,
      75             :                                             Handle<String> string,
      76             :                                             Handle<Object> exec) {
      77        1878 :   if (exec->IsUndefined(isolate)) {
      78        3756 :     ASSIGN_RETURN_ON_EXCEPTION(
      79             :         isolate, exec,
      80             :         Object::GetProperty(isolate, regexp, isolate->factory()->exec_string()),
      81             :         Object);
      82             :   }
      83             : 
      84        1878 :   if (exec->IsCallable()) {
      85             :     const int argc = 1;
      86             :     ScopedVector<Handle<Object>> argv(argc);
      87        1842 :     argv[0] = string;
      88             : 
      89             :     Handle<Object> result;
      90        3684 :     ASSIGN_RETURN_ON_EXCEPTION(
      91             :         isolate, result,
      92             :         Execution::Call(isolate, exec, regexp, argc, argv.start()), Object);
      93             : 
      94        2677 :     if (!result->IsJSReceiver() && !result->IsNull(isolate)) {
      95           0 :       THROW_NEW_ERROR(isolate,
      96             :                       NewTypeError(MessageTemplate::kInvalidRegExpExecResult),
      97             :                       Object);
      98             :     }
      99        1833 :     return result;
     100             :   }
     101             : 
     102          36 :   if (!regexp->IsJSRegExp()) {
     103           0 :     THROW_NEW_ERROR(isolate,
     104             :                     NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
     105             :                                  isolate->factory()->NewStringFromAsciiChecked(
     106             :                                      "RegExp.prototype.exec"),
     107             :                                  regexp),
     108             :                     Object);
     109             :   }
     110             : 
     111             :   {
     112          36 :     Handle<JSFunction> regexp_exec = isolate->regexp_exec_function();
     113             : 
     114             :     const int argc = 1;
     115             :     ScopedVector<Handle<Object>> argv(argc);
     116          36 :     argv[0] = string;
     117             : 
     118          36 :     return Execution::Call(isolate, regexp_exec, regexp, argc, argv.start());
     119             :   }
     120             : }
     121             : 
     122         432 : Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) {
     123         432 :   if (!object->IsJSReceiver()) return Just(false);
     124             : 
     125         162 :   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
     126             : 
     127             :   Handle<Object> match;
     128         324 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     129             :       isolate, match,
     130             :       JSObject::GetProperty(isolate, receiver,
     131             :                             isolate->factory()->match_symbol()),
     132             :       Nothing<bool>());
     133             : 
     134         162 :   if (!match->IsUndefined(isolate)) {
     135          81 :     const bool match_as_boolean = match->BooleanValue(isolate);
     136             : 
     137         153 :     if (match_as_boolean && !object->IsJSRegExp()) {
     138           0 :       isolate->CountUsage(v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp);
     139          90 :     } else if (!match_as_boolean && object->IsJSRegExp()) {
     140           9 :       isolate->CountUsage(v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp);
     141             :     }
     142             : 
     143             :     return Just(match_as_boolean);
     144             :   }
     145             : 
     146             :   return Just(object->IsJSRegExp());
     147             : }
     148             : 
     149        6189 : bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
     150             : #ifdef V8_ENABLE_FORCE_SLOW_PATH
     151             :   if (isolate->force_slow_path()) return false;
     152             : #endif
     153             : 
     154        6189 :   if (!obj->IsJSReceiver()) return false;
     155             : 
     156             :   JSReceiver recv = JSReceiver::cast(*obj);
     157             : 
     158        6189 :   if (!HasInitialRegExpMap(isolate, recv)) return false;
     159             : 
     160             :   // Check the receiver's prototype's map.
     161             :   Object proto = recv->map()->prototype();
     162        5802 :   if (!proto->IsJSReceiver()) return false;
     163             : 
     164        5802 :   Handle<Map> initial_proto_initial_map = isolate->regexp_prototype_map();
     165             :   Map proto_map = JSReceiver::cast(proto)->map();
     166        5802 :   if (proto_map != *initial_proto_initial_map) {
     167             :     return false;
     168             :   }
     169             : 
     170             :   // Check that the "exec" method is unmodified.
     171             :   if (FLAG_track_constant_fields) {
     172             :     // Check that the index refers to "exec" method (this has to be consistent
     173             :     // with the init order in the bootstrapper).
     174             :     DCHECK_EQ(*(isolate->factory()->exec_string()),
     175             :               proto_map->instance_descriptors()->GetKey(
     176             :                   JSRegExp::kExecFunctionDescriptorIndex));
     177        5721 :     if (proto_map->instance_descriptors()
     178             :             ->GetDetails(JSRegExp::kExecFunctionDescriptorIndex)
     179             :             .constness() != PropertyConstness::kConst) {
     180             :       return false;
     181             :     }
     182             :   }
     183             : 
     184        5703 :   if (!isolate->IsRegExpSpeciesLookupChainIntact()) return false;
     185             : 
     186             :   // The smi check is required to omit ToLength(lastIndex) calls with possible
     187             :   // user-code execution on the fast path.
     188             :   Object last_index = JSRegExp::cast(recv)->last_index();
     189       11379 :   return last_index->IsSmi() && Smi::ToInt(last_index) >= 0;
     190             : }
     191             : 
     192         646 : uint64_t RegExpUtils::AdvanceStringIndex(Handle<String> string, uint64_t index,
     193             :                                          bool unicode) {
     194             :   DCHECK_LE(static_cast<double>(index), kMaxSafeInteger);
     195         646 :   const uint64_t string_length = static_cast<uint64_t>(string->length());
     196         646 :   if (unicode && index < string_length) {
     197          18 :     const uint16_t first = string->Get(static_cast<uint32_t>(index));
     198          18 :     if (first >= 0xD800 && first <= 0xDBFF && index + 1 < string_length) {
     199             :       DCHECK_LT(index, std::numeric_limits<uint64_t>::max());
     200           0 :       const uint16_t second = string->Get(static_cast<uint32_t>(index + 1));
     201           0 :       if (second >= 0xDC00 && second <= 0xDFFF) {
     202           0 :         return index + 2;
     203             :       }
     204             :     }
     205             :   }
     206             : 
     207         646 :   return index + 1;
     208             : }
     209             : 
     210          90 : MaybeHandle<Object> RegExpUtils::SetAdvancedStringIndex(
     211             :     Isolate* isolate, Handle<JSReceiver> regexp, Handle<String> string,
     212             :     bool unicode) {
     213             :   Handle<Object> last_index_obj;
     214         180 :   ASSIGN_RETURN_ON_EXCEPTION(
     215             :       isolate, last_index_obj,
     216             :       Object::GetProperty(isolate, regexp,
     217             :                           isolate->factory()->lastIndex_string()),
     218             :       Object);
     219             : 
     220         180 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
     221             :                              Object::ToLength(isolate, last_index_obj), Object);
     222             :   const uint64_t last_index = PositiveNumberToUint64(*last_index_obj);
     223             :   const uint64_t new_last_index =
     224          90 :       AdvanceStringIndex(string, last_index, unicode);
     225             : 
     226          90 :   return SetLastIndex(isolate, regexp, new_last_index);
     227             : }
     228             : 
     229             : }  // namespace internal
     230      121996 : }  // namespace v8

Generated by: LCOV version 1.10