%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/test/cctest/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/test/cctest/test-regexp.cc

// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "include/v8-function.h"
#include "include/v8-regexp.h"
#include "src/api/api-inl.h"
#include "src/execution/frames-inl.h"
#include "test/cctest/cctest.h"
#include "test/cctest/heap/heap-utils.h"

using namespace v8;

namespace {

const char kOneByteSubjectString[] = {
    'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0'};
const uint16_t kTwoByteSubjectString[] = {
    0xCF80, 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    'a',    'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    'a',    'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0'};

const int kSubjectStringLength = arraysize(kOneByteSubjectString) - 1;
static_assert(arraysize(kOneByteSubjectString) ==
              arraysize(kTwoByteSubjectString));

class OneByteVectorResource : public String::ExternalOneByteStringResource {
 public:
  explicit OneByteVectorResource(base::Vector<const char> vector)
      : data_(vector) {}
  ~OneByteVectorResource() override = default;
  size_t length() const override { return data_.length(); }
  const char* data() const override { return data_.begin(); }
  void Dispose() override {}

 private:
  base::Vector<const char> data_;
};

class UC16VectorResource : public String::ExternalStringResource {
 public:
  explicit UC16VectorResource(base::Vector<const base::uc16> vector)
      : data_(vector) {}
  ~UC16VectorResource() override = default;
  size_t length() const override { return data_.length(); }
  const base::uc16* data() const override { return data_.begin(); }
  void Dispose() override {}

 private:
  base::Vector<const base::uc16> data_;
};

OneByteVectorResource one_byte_string_resource(
    base::Vector<const char>(&kOneByteSubjectString[0], kSubjectStringLength));
UC16VectorResource two_byte_string_resource(base::Vector<const base::uc16>(
    &kTwoByteSubjectString[0], kSubjectStringLength));

class InterruptTest {
 public:
  InterruptTest()
      : i_thread(this),
        env_(),
        isolate_(env_->GetIsolate()),
        sem_(0),
        ran_test_body_(false),
        ran_to_completion_(false) {}

  void RunTest(InterruptCallback test_body_fn) {
    HandleScope handle_scope(isolate_);
    Local<RegExp> re =
        RegExp::New(env_.local(), v8_str("((a*)*)*b"), v8::RegExp::kNone)
            .ToLocalChecked();
    regexp_handle_.Reset(isolate_, re);
    i_thread.SetTestBody(test_body_fn);
    CHECK(i_thread.Start());
    TestBody();
    i_thread.Join();
  }

  static void InvokeMajorGC(Isolate* isolate, void* data) {
    i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
    i::heap::InvokeAtomicMajorGC(i_isolate->heap());
  }

  static void MakeSubjectOneByteExternal(Isolate* isolate, void* data) {
    auto instance = reinterpret_cast<InterruptTest*>(data);
    HandleScope scope(isolate);
    Local<String> string =
        Local<String>::New(isolate, instance->subject_string_handle_);
    CHECK(string->CanMakeExternal(String::Encoding::ONE_BYTE_ENCODING));
    string->MakeExternal(&one_byte_string_resource);
  }

  static void MakeSubjectTwoByteExternal(Isolate* isolate, void* data) {
    auto instance = reinterpret_cast<InterruptTest*>(data);
    HandleScope scope(isolate);
    Local<String> string =
        Local<String>::New(isolate, instance->subject_string_handle_);
    CHECK(string->CanMakeExternal(String::Encoding::TWO_BYTE_ENCODING));
    string->MakeExternal(&two_byte_string_resource);
  }

  static void TwoByteSubjectToOneByte(Isolate* isolate, void* data) {
    auto instance = reinterpret_cast<InterruptTest*>(data);
    HandleScope scope(isolate);
    Local<RegExp> re = instance->regexp_handle_.Get(isolate);
    i::Handle<i::JSRegExp> regexp = Utils::OpenHandle(*re);
    // We executed on a two-byte subject so far, so we expect only bytecode for
    // two-byte to be present.
    i::Tagged<i::Object> one_byte_code = regexp->bytecode(/* is_latin1 */ true);
    CHECK(IsSmi(one_byte_code));
    CHECK_EQ(i::Smi::cast(one_byte_code).value(),
             i::JSRegExp::kUninitializedValue);
    i::Tagged<i::Object> two_byte_code =
        regexp->bytecode(/* is_latin1 */ false);
    CHECK(IsByteArray(two_byte_code));

    // Transition the subject string to one-byte by internalizing it.
    // It already contains only one-byte characters.
    Local<String> string = instance->GetSubjectString();
    CHECK(!string->IsOneByte());
    CHECK(string->ContainsOnlyOneByte());
    // Internalize the subject by using it as a computed property name in an
    // object.
    CompileRun("o = { [subject_string]: 'foo' }");
    CHECK(string->IsOneByte());
  }

  static void IterateStack(Isolate* isolate, void* data) {
    HandleScope scope(isolate);

    i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
    v8::RegisterState state;
#if defined(USE_SIMULATOR)
    SimulatorHelper simulator_helper;
    if (!simulator_helper.Init(isolate)) return;
    simulator_helper.FillRegisters(&state);
#else
    state.pc = nullptr;
    state.fp = &state;
    state.sp = &state;
#endif

    i::StackFrameIteratorForProfilerForTesting it(
        i_isolate, reinterpret_cast<i::Address>(state.pc),
        reinterpret_cast<i::Address>(state.fp),
        reinterpret_cast<i::Address>(state.sp),
        reinterpret_cast<i::Address>(state.lr), i_isolate->js_entry_sp());

    for (; !it.done(); it.Advance()) {
      // Ideally we'd access the frame a bit (doesn't matter how); but this
      // iterator is very limited in what it may access, and prints run into
      // DCHECKs. So we can't do this:
      // it.frame()->Print(&accumulator, i::StackFrame::OVERVIEW,
      //                   frame_index++);
    }
  }

  void SetOneByteSubjectString() {
    HandleScope handle_scope(isolate_);
    i::Isolate* i_isolate = this->i_isolate();
    // The string must be in old space to support externalization.
    i::Handle<i::String> i_one_byte_string =
        i_isolate->factory()->NewStringFromAsciiChecked(
            &kOneByteSubjectString[0], i::AllocationType::kOld);
    SetSubjectString(Utils::ToLocal(i_one_byte_string));
  }

  void SetTwoByteSubjectString() {
    HandleScope handle_scope(isolate_);
    i::Isolate* i_isolate = this->i_isolate();
    // The string must be in old space to support externalization.
    i::Handle<i::String> i_two_byte_string =
        i_isolate->factory()
            ->NewStringFromTwoByte(
                base::Vector<const base::uc16>(&kTwoByteSubjectString[0],
                                               kSubjectStringLength),
                i::AllocationType::kOld)
            .ToHandleChecked();
    SetSubjectString(Utils::ToLocal(i_two_byte_string));
  }

  void SetSubjectString(Local<String> subject) {
    env_->Global()
        ->Set(env_.local(), v8_str("subject_string"), subject)
        .FromJust();
    subject_string_handle_.Reset(env_->GetIsolate(), subject);
  }

  Local<String> GetSubjectString() const {
    return subject_string_handle_.Get(isolate_);
  }

  Local<RegExp> GetRegExp() const { return regexp_handle_.Get(isolate_); }

  i::Isolate* i_isolate() const {
    return reinterpret_cast<i::Isolate*>(isolate_);
  }

 private:
  static void SignalSemaphore(Isolate* isolate, void* data) {
    reinterpret_cast<InterruptTest*>(data)->sem_.Signal();
  }

  void TestBody() {
    CHECK(!ran_test_body_.load());
    CHECK(!ran_to_completion_.load());

    DCHECK(!subject_string_handle_.IsEmpty());

    TryCatch try_catch(env_->GetIsolate());

    isolate_->RequestInterrupt(&SignalSemaphore, this);
    MaybeLocal<Object> result = regexp_handle_.Get(isolate_)->Exec(
        env_.local(), subject_string_handle_.Get(isolate_));
    CHECK(result.IsEmpty());

    CHECK(try_catch.HasTerminated());
    CHECK(ran_test_body_.load());
    CHECK(ran_to_completion_.load());
  }

  class InterruptThread : public base::Thread {
   public:
    explicit InterruptThread(InterruptTest* test)
        : Thread(Options("InterruptTest")), test_(test) {}

    void Run() override {
      CHECK_NOT_NULL(test_body_fn_);

      // Wait for JS execution to start.
      test_->sem_.Wait();

      // Sleep for a bit to allow irregexp execution to start up, then run the
      // test body.
      base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
      test_->isolate_->RequestInterrupt(&RunTestBody, test_);
      test_->isolate_->RequestInterrupt(&SignalSemaphore, test_);

      // Wait for the scheduled interrupt to signal.
      test_->sem_.Wait();

      // Sleep again to resume irregexp execution, then terminate.
      base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
      test_->ran_to_completion_.store(true);
      test_->isolate_->TerminateExecution();
    }

    static void RunTestBody(Isolate* isolate, void* data) {
      auto instance = reinterpret_cast<InterruptTest*>(data);
      instance->i_thread.test_body_fn_(isolate, data);
      instance->ran_test_body_.store(true);
    }

    void SetTestBody(InterruptCallback callback) { test_body_fn_ = callback; }

   private:
    InterruptCallback test_body_fn_;
    InterruptTest* test_;
  };

  InterruptThread i_thread;

  LocalContext env_;
  Isolate* isolate_;
  base::Semaphore sem_;  // Coordinates between main and interrupt threads.

  Persistent<String> subject_string_handle_;
  Persistent<RegExp> regexp_handle_;

  std::atomic<bool> ran_test_body_;
  std::atomic<bool> ran_to_completion_;
};

void SetCommonV8FlagsForInterruptTests() {
  // Interrupt tests rely on quirks of the backtracking engine to trigger
  // pattern execution long enough s.t. we can reliably trigger an interrupt
  // while the regexp code is still executing.
  i::v8_flags.enable_experimental_regexp_engine_on_excessive_backtracks = false;
}

}  // namespace

TEST(InterruptAndInvokeMajorGC) {
  // Move all movable objects on GC.
  i::v8_flags.compact_on_every_full_gc = true;
  SetCommonV8FlagsForInterruptTests();
  InterruptTest test{};
  test.SetOneByteSubjectString();
  test.RunTest(InterruptTest::InvokeMajorGC);
}

TEST(InterruptAndMakeSubjectOneByteExternal) {
  SetCommonV8FlagsForInterruptTests();
  InterruptTest test{};
  test.SetOneByteSubjectString();
  test.RunTest(InterruptTest::MakeSubjectOneByteExternal);
}

TEST(InterruptAndMakeSubjectTwoByteExternal) {
  SetCommonV8FlagsForInterruptTests();
  InterruptTest test{};
  test.SetTwoByteSubjectString();
  test.RunTest(InterruptTest::MakeSubjectTwoByteExternal);
}

TEST(InterruptAndIterateStack) {
  i::v8_flags.regexp_tier_up = false;
  SetCommonV8FlagsForInterruptTests();
  InterruptTest test{};
  test.SetOneByteSubjectString();
  test.RunTest(InterruptTest::IterateStack);
}

TEST(InterruptAndTransitionSubjectFromTwoByteToOneByte) {
  SetCommonV8FlagsForInterruptTests();
  InterruptTest test{};
  i::Isolate* i_isolate = test.i_isolate();
  i::HandleScope handle_scope(i_isolate);
  // Internalize a one-byte copy of the two-byte string we are going to
  // internalize during the interrupt. This ensures that the two-byte string
  // transitions to a ThinString pointing to a one-byte string.
  Local<String> internalized_string =
      String::NewFromUtf8(
          reinterpret_cast<Isolate*>(i_isolate), &kOneByteSubjectString[1],
          v8::NewStringType::kInternalized, kSubjectStringLength - 1)
          .ToLocalChecked();
  CHECK(internalized_string->IsOneByte());

  test.SetTwoByteSubjectString();
  Local<String> string = test.GetSubjectString();
  CHECK(!string->IsOneByte());
  // Set the subject string as a substring of the original subject (containing
  // only one-byte characters).
  v8::Local<Value> value =
      CompileRun("subject_string = subject_string.substring(1)");
  test.SetSubjectString(value.As<String>());
  CHECK(test.GetSubjectString()->ContainsOnlyOneByte());

  test.RunTest(InterruptTest::TwoByteSubjectToOneByte);
  // After the test, we expect that bytecode for a one-byte subject has been
  // installed during the interrupt.
  i::Handle<i::JSRegExp> regexp = Utils::OpenHandle(*test.GetRegExp());
  i::Tagged<i::Object> one_byte_code = regexp->bytecode(/* is_latin1 */ true);
  CHECK(IsByteArray(one_byte_code));
}

Zerion Mini Shell 1.0