text: // Copyright 2017 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 "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
  
  #include "src/api/api-inl.h"
  #include "src/base/atomic-utils.h"
  #include "src/base/platform/semaphore.h"
  #include "src/codegen/compiler.h"
  #include "src/codegen/optimized-compilation-info.h"
  #include "src/execution/isolate.h"
  #include "src/handles/handles.h"
  #include "src/objects/objects-inl.h"
  #include "src/parsing/parse-info.h"
  #include "test/unittests/test-helpers.h"
  #include "test/unittests/test-utils.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace v8 {
  namespace internal {
  
  using OptimizingCompileDispatcherTest = TestWithNativeContext;
  
  namespace {
  
  static constexpr bool kNativeContextDependent = false;
  
  class BlockingCompilationJob : public OptimizedCompilationJob {
   public:
    BlockingCompilationJob(Isolate* isolate, Handle<JSFunction> function)
        : OptimizedCompilationJob(&info_, "BlockingCompilationJob",
                                  State::kReadyToExecute),
          shared_(function->shared(), isolate),
          zone_(isolate->allocator(), ZONE_NAME),
          info_(&zone_, isolate, shared_, function, kNativeContextDependent),
          blocking_(false),
          semaphore_(0) {}
    ~BlockingCompilationJob() override = default;
  
    bool IsBlocking() const { return blocking_.Value(); }
    void Signal() { semaphore_.Signal(); }
  
    // OptimiziedCompilationJob implementation.
    Status PrepareJobImpl(Isolate* isolate) override { UNREACHABLE(); }
  
    Status ExecuteJobImpl(RuntimeCallStats* stats) override {
      blocking_.SetValue(true);
      semaphore_.Wait();
      blocking_.SetValue(false);
      return SUCCEEDED;
    }
  
    Status FinalizeJobImpl(Isolate* isolate) override { return SUCCEEDED; }
  
   private:
    Handle<SharedFunctionInfo> shared_;
    Zone zone_;
    OptimizedCompilationInfo info_;
    base::AtomicValue<bool> blocking_;
    base::Semaphore semaphore_;
  
    DISALLOW_COPY_AND_ASSIGN(BlockingCompilationJob);
  };
  
  }  // namespace
  
  TEST_F(OptimizingCompileDispatcherTest, Construct) {
    OptimizingCompileDispatcher dispatcher(i_isolate());
    ASSERT_TRUE(OptimizingCompileDispatcher::Enabled());
    ASSERT_TRUE(dispatcher.IsQueueAvailable());
  }
  
  TEST_F(OptimizingCompileDispatcherTest, NonBlockingFlush) {
    Handle<JSFunction> fun =
        RunJS<JSFunction>("function f() { function g() {}; return g;}; f();");
    IsCompiledScope is_compiled_scope;
    ASSERT_TRUE(
        Compiler::Compile(fun, Compiler::CLEAR_EXCEPTION, &is_compiled_scope));
    BlockingCompilationJob* job = new BlockingCompilationJob(i_isolate(), fun);
  
    OptimizingCompileDispatcher dispatcher(i_isolate());
    ASSERT_TRUE(OptimizingCompileDispatcher::Enabled());
    ASSERT_TRUE(dispatcher.IsQueueAvailable());
    dispatcher.QueueForOptimization(job);
  
    // Busy-wait for the job to run on a background thread.
    while (!job->IsBlocking()) {
    }
  
    // Should not block.
    dispatcher.Flush(BlockingBehavior::kDontBlock);
  
    // Unblock the job & finish.
    job->Signal();
    dispatcher.Stop();
  }
  
  }  // namespace internal
  }  // namespace v8
  