Commit 6ff1129c authored by Patrick Thier's avatar Patrick Thier Committed by V8 LUCI CQ

[sparkplug] Batch compilation

Instead of compiling a function with baseline immediately when the
interrupt budget is hit, we compile functions in batches to save some
memory protection flips on code pages.

This CL introduces batch compilation behind --baseline-batch-compilation
(enabled on future) and adds a flag
--baseline-batch-compilation-threshold to control the size of batches.

Bug: v8:11790

Change-Id: I3efc360424a14e4b07c6570e48860509ae59e591
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2891656Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74913}
parent dd329e19
......@@ -2376,6 +2376,7 @@ v8_header_set("v8_internal_headers") {
"src/ast/variables.h",
"src/baseline/baseline-assembler-inl.h",
"src/baseline/baseline-assembler.h",
"src/baseline/baseline-batch-compiler.h",
"src/baseline/baseline-compiler.h",
"src/baseline/baseline-osr-inl.h",
"src/baseline/baseline.h",
......@@ -3656,6 +3657,7 @@ v8_source_set("v8_base_without_compiler") {
"src/ast/scopes.cc",
"src/ast/source-range-ast-visitor.cc",
"src/ast/variables.cc",
"src/baseline/baseline-batch-compiler.cc",
"src/baseline/baseline-compiler.cc",
"src/baseline/baseline.cc",
"src/baseline/bytecode-offset-iterator.cc",
......
......@@ -5,6 +5,7 @@ include_rules = [
"+src/asmjs/asm-js.h",
"-src/baseline",
"+src/baseline/baseline.h",
"+src/baseline/baseline-batch-compiler.h",
"+src/baseline/baseline-osr-inl.h",
"+src/baseline/bytecode-offset-iterator.h",
"-src/bigint",
......
......@@ -25,6 +25,7 @@
#include "src/base/platform/time.h"
#include "src/base/safe_conversions.h"
#include "src/base/utils/random-number-generator.h"
#include "src/baseline/baseline-batch-compiler.h"
#include "src/builtins/accessors.h"
#include "src/builtins/builtins-utils.h"
#include "src/codegen/compiler.h"
......@@ -409,6 +410,8 @@ SnapshotCreator::SnapshotCreator(Isolate* isolate,
internal_isolate->InitWithoutSnapshot();
}
data_ = data;
// Disable batch compilation during snapshot creation.
internal_isolate->baseline_batch_compiler()->set_enabled(false);
}
SnapshotCreator::SnapshotCreator(const intptr_t* external_references,
......
// Copyright 2021 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/baseline/baseline-batch-compiler.h"
#include "src/baseline/baseline-compiler.h"
#include "src/codegen/compiler.h"
#include "src/execution/isolate.h"
#include "src/heap/factory-inl.h"
#include "src/objects/fixed-array-inl.h"
#include "src/objects/js-function-inl.h"
namespace v8 {
namespace internal {
namespace baseline {
BaselineBatchCompiler::BaselineBatchCompiler(Isolate* isolate)
: isolate_(isolate),
compilation_queue_(Handle<WeakFixedArray>::null()),
last_index_(0),
estimated_instruction_size_(0),
enabled_(true) {}
BaselineBatchCompiler::~BaselineBatchCompiler() {
if (!compilation_queue_.is_null()) {
GlobalHandles::Destroy(compilation_queue_.location());
compilation_queue_ = Handle<WeakFixedArray>::null();
}
}
bool BaselineBatchCompiler::EnqueueFunction(Handle<JSFunction> function) {
HandleScope scope(isolate_);
Handle<SharedFunctionInfo> shared(function->shared(), isolate_);
// Early return if the function is compiled with baseline already or it is not
// suitable for baseline compilation.
if (shared->HasBaselineData()) return true;
if (!CanCompileWithBaseline(isolate_, shared)) return false;
// Immediately compile the function if batch compilation is disabled.
if (!is_enabled()) {
IsCompiledScope is_compiled_scope(
function->shared().is_compiled_scope(isolate_));
return Compiler::CompileBaseline(
isolate_, function, Compiler::CLEAR_EXCEPTION, &is_compiled_scope);
}
{
DisallowHeapAllocation no_gc;
estimated_instruction_size_ += BaselineCompiler::EstimateInstructionSize(
shared->GetBytecodeArray(isolate_));
}
if (ShouldCompileBatch()) {
CompileBatch(function);
return true;
}
EnsureQueueCapacity();
compilation_queue_->Set(last_index_++, HeapObjectReference::Weak(*shared));
return false;
}
void BaselineBatchCompiler::EnsureQueueCapacity() {
if (compilation_queue_.is_null()) {
compilation_queue_ = isolate_->global_handles()->Create(
*isolate_->factory()->NewWeakFixedArray(kInitialQueueSize,
AllocationType::kOld));
return;
}
if (last_index_ >= compilation_queue_->length()) {
Handle<WeakFixedArray> new_queue =
isolate_->factory()->CopyWeakFixedArrayAndGrow(compilation_queue_,
last_index_);
GlobalHandles::Destroy(compilation_queue_.location());
compilation_queue_ = isolate_->global_handles()->Create(*new_queue);
}
}
void BaselineBatchCompiler::CompileBatch(Handle<JSFunction> function) {
HandleScope scope(isolate_);
CodePageCollectionMemoryModificationScope batch_allocation(isolate_->heap());
{
IsCompiledScope is_compiled_scope(
function->shared().is_compiled_scope(isolate_));
Compiler::CompileBaseline(isolate_, function, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope);
}
for (int i = 0; i < last_index_; i++) {
MaybeObject maybe_sfi = compilation_queue_->Get(i);
MaybeCompileFunction(maybe_sfi);
compilation_queue_->Set(i, HeapObjectReference::ClearedValue(isolate_));
}
ClearBatch();
}
bool BaselineBatchCompiler::ShouldCompileBatch() const {
return estimated_instruction_size_ >=
FLAG_baseline_batch_compilation_threshold;
}
bool BaselineBatchCompiler::MaybeCompileFunction(MaybeObject maybe_sfi) {
HeapObject heapobj;
// Skip functions where the weak reference is no longer valid.
if (!maybe_sfi.GetHeapObjectIfWeak(&heapobj)) return false;
Handle<SharedFunctionInfo> shared =
handle(SharedFunctionInfo::cast(heapobj), isolate_);
// Skip functions where the bytecode has been flushed.
if (!shared->is_compiled()) return false;
IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate_));
return Compiler::CompileSharedWithBaseline(
isolate_, shared, Compiler::CLEAR_EXCEPTION, &is_compiled_scope);
}
void BaselineBatchCompiler::ClearBatch() {
estimated_instruction_size_ = 0;
last_index_ = 0;
}
} // namespace baseline
} // namespace internal
} // namespace v8
// Copyright 2021 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.
#ifndef V8_BASELINE_BASELINE_BATCH_COMPILER_H_
#define V8_BASELINE_BASELINE_BATCH_COMPILER_H_
#include "src/handles/global-handles.h"
#include "src/handles/handles.h"
namespace v8 {
namespace internal {
namespace baseline {
class BaselineBatchCompiler {
public:
static const int kInitialQueueSize = 4;
explicit BaselineBatchCompiler(Isolate* isolate);
~BaselineBatchCompiler();
// Enqueues SharedFunctionInfo of |function| for compilation.
// Returns true if the function is compiled (either it was compiled already,
// or the current batch including the function was just compiled).
bool EnqueueFunction(Handle<JSFunction> function);
void set_enabled(bool enabled) { enabled_ = enabled; }
bool is_enabled() { return enabled_; }
private:
// Ensure there is enough space in the compilation queue to enqueue another
// function, growing the queue if necessary.
void EnsureQueueCapacity();
// Returns true if the current batch exceeds the threshold and should be
// compiled.
bool ShouldCompileBatch() const;
// Compiles the current batch and returns the number of functions compiled.
void CompileBatch(Handle<JSFunction> function);
// Resets the current batch.
void ClearBatch();
// Tries to compile |maybe_sfi|. Returns false if compilation was not possible
// (e.g. bytecode was fushed, weak handle no longer valid, ...).
bool MaybeCompileFunction(MaybeObject maybe_sfi);
Isolate* isolate_;
// Global handle to shared function infos enqueued for compilation in the
// current batch.
Handle<WeakFixedArray> compilation_queue_;
// Last index set in compilation_queue_;
int last_index_;
// Estimated insturction size of current batch.
int estimated_instruction_size_;
// Flag indicating whether batch compilation is enabled.
// Batch compilation can be dynamically disabled e.g. when creating snapshots.
bool enabled_;
};
} // namespace baseline
} // namespace internal
} // namespace v8
#endif // V8_BASELINE_BASELINE_BATCH_COMPILER_H_
......@@ -241,7 +241,11 @@ const int kAverageBytecodeToInstructionRatio = 7;
#endif
std::unique_ptr<AssemblerBuffer> AllocateBuffer(
Handle<BytecodeArray> bytecodes) {
int estimated_size = bytecodes->length() * kAverageBytecodeToInstructionRatio;
int estimated_size;
{
DisallowHeapAllocation no_gc;
estimated_size = BaselineCompiler::EstimateInstructionSize(*bytecodes);
}
return NewAssemblerBuffer(RoundUp(estimated_size, 4 * KB));
}
} // namespace
......@@ -305,6 +309,10 @@ MaybeHandle<Code> BaselineCompiler::Build(Isolate* isolate) {
.TryBuild();
}
int BaselineCompiler::EstimateInstructionSize(BytecodeArray bytecode) {
return bytecode.length() * kAverageBytecodeToInstructionRatio;
}
interpreter::Register BaselineCompiler::RegisterOperand(int operand_index) {
return iterator().GetRegisterOperand(operand_index);
}
......
......@@ -57,6 +57,7 @@ class BaselineCompiler {
void GenerateCode();
MaybeHandle<Code> Build(Isolate* isolate);
static int EstimateInstructionSize(BytecodeArray bytecode);
private:
void Prologue();
......
......@@ -5,19 +5,33 @@
#ifndef V8_BASELINE_BASELINE_OSR_INL_H_
#define V8_BASELINE_BASELINE_OSR_INL_H_
#include "src/baseline/baseline-batch-compiler.h"
#include "src/execution/frames.h"
#include "src/execution/isolate-inl.h"
namespace v8 {
namespace internal {
enum CompilationMode { kCompileImmediate, kCompileBatch };
inline void OSRInterpreterFrameToBaseline(Isolate* isolate,
Handle<JSFunction> function,
UnoptimizedFrame* frame) {
UnoptimizedFrame* frame,
CompilationMode compilation_mode) {
IsCompiledScope is_compiled_scope(
function->shared().is_compiled_scope(isolate));
if (Compiler::CompileBaseline(isolate, function, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope)) {
bool is_compiled = false;
switch (compilation_mode) {
case kCompileBatch:
is_compiled =
isolate->baseline_batch_compiler()->EnqueueFunction(function);
break;
case kCompileImmediate:
is_compiled = Compiler::CompileBaseline(
isolate, function, Compiler::CLEAR_EXCEPTION, &is_compiled_scope);
break;
}
if (is_compiled) {
if (V8_LIKELY(FLAG_use_osr)) {
DCHECK_NOT_NULL(frame);
if (FLAG_trace_osr) {
......
......@@ -13,6 +13,7 @@
#include "src/baseline/baseline-assembler-inl.h"
#include "src/baseline/baseline-compiler.h"
#include "src/debug/debug.h"
#include "src/heap/factory-inl.h"
#include "src/logging/counters.h"
#include "src/objects/script-inl.h"
......@@ -21,6 +22,26 @@
namespace v8 {
namespace internal {
bool CanCompileWithBaseline(Isolate* isolate,
Handle<SharedFunctionInfo> shared) {
// Check that baseline compiler is enabled.
if (!FLAG_sparkplug) return false;
// Check if we actually have bytecode.
if (!shared->HasBytecodeArray()) return false;
// Do not optimize when debugger needs to hook into every call.
if (isolate->debug()->needs_check_on_function_call()) return false;
// Functions with breakpoints have to stay interpreted.
if (shared->HasBreakInfo()) return false;
// Do not baseline compile if function doesn't pass sparkplug_filter.
if (!shared->PassesFilter(FLAG_sparkplug_filter)) return false;
return true;
}
MaybeHandle<Code> GenerateBaselineCode(Isolate* isolate,
Handle<SharedFunctionInfo> shared) {
RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileBaseline);
......
......@@ -14,6 +14,9 @@ class Code;
class SharedFunctionInfo;
class MacroAssembler;
bool CanCompileWithBaseline(Isolate* isolate,
Handle<SharedFunctionInfo> shared);
MaybeHandle<Code> GenerateBaselineCode(Isolate* isolate,
Handle<SharedFunctionInfo> shared);
......
......@@ -641,77 +641,6 @@ void UpdateSharedFunctionFlagsAfterCompilation(FunctionLiteral* literal,
shared_info.SetScopeInfo(*literal->scope()->scope_info());
}
bool CanCompileWithBaseline(Isolate* isolate,
Handle<SharedFunctionInfo> shared) {
// Check if we actually have bytecode.
if (!shared->HasBytecodeArray()) return false;
// Do not optimize when debugger needs to hook into every call.
if (isolate->debug()->needs_check_on_function_call()) return false;
// Functions with breakpoints have to stay interpreted.
if (shared->HasBreakInfo()) return false;
// Do not baseline compile if sparkplug is disabled or function doesn't pass
// sparkplug_filter.
if (!FLAG_sparkplug || !shared->PassesFilter(FLAG_sparkplug_filter)) {
return false;
}
return true;
}
bool CompileSharedWithBaseline(Isolate* isolate,
Handle<SharedFunctionInfo> shared,
Compiler::ClearExceptionFlag flag,
IsCompiledScope* is_compiled_scope) {
// We shouldn't be passing uncompiled functions into this function.
DCHECK(is_compiled_scope->is_compiled());
// Early return for already baseline-compiled functions.
if (shared->HasBaselineData()) return true;
// Check if we actually can compile with baseline.
if (!CanCompileWithBaseline(isolate, shared)) return false;
StackLimitCheck check(isolate);
if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
if (flag == Compiler::KEEP_EXCEPTION) {
isolate->StackOverflow();
}
return false;
}
CompilerTracer::TraceStartBaselineCompile(isolate, shared);
Handle<Code> code;
base::TimeDelta time_taken;
{
ScopedTimer timer(&time_taken);
if (!GenerateBaselineCode(isolate, shared).ToHandle(&code)) {
// TODO(leszeks): This can only fail because of an OOM. Do we want to
// report these somehow, or silently ignore them?
return false;
}
Handle<HeapObject> function_data =
handle(HeapObject::cast(shared->function_data(kAcquireLoad)), isolate);
Handle<BaselineData> baseline_data =
isolate->factory()->NewBaselineData(code, function_data);
shared->set_baseline_data(*baseline_data);
}
double time_taken_ms = time_taken.InMillisecondsF();
CompilerTracer::TraceFinishBaselineCompile(isolate, shared, time_taken_ms);
if (shared->script().IsScript()) {
Compiler::LogFunctionCompilation(
isolate, CodeEventListener::FUNCTION_TAG, shared,
handle(Script::cast(shared->script()), isolate),
Handle<AbstractCode>::cast(code), CodeKind::BASELINE, time_taken_ms);
}
return true;
}
// Finalize a single compilation job. This function can return
// RETRY_ON_MAIN_THREAD if the job cannot be finalized off-thread, in which case
// it should be safe to call it again on the main thread with the same job.
......@@ -1381,8 +1310,8 @@ void CompileAllWithBaseline(Isolate* isolate,
IsCompiledScope is_compiled_scope(*shared_info, isolate);
if (!is_compiled_scope.is_compiled()) continue;
if (!CanCompileWithBaseline(isolate, shared_info)) continue;
CompileSharedWithBaseline(isolate, shared_info, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope);
Compiler::CompileSharedWithBaseline(
isolate, shared_info, Compiler::CLEAR_EXCEPTION, &is_compiled_scope);
}
}
......@@ -1998,6 +1927,58 @@ bool Compiler::Compile(Isolate* isolate, Handle<JSFunction> function,
return true;
}
// static
bool Compiler::CompileSharedWithBaseline(Isolate* isolate,
Handle<SharedFunctionInfo> shared,
Compiler::ClearExceptionFlag flag,
IsCompiledScope* is_compiled_scope) {
// We shouldn't be passing uncompiled functions into this function.
DCHECK(is_compiled_scope->is_compiled());
// Early return for already baseline-compiled functions.
if (shared->HasBaselineData()) return true;
// Check if we actually can compile with baseline.
if (!CanCompileWithBaseline(isolate, shared)) return false;
StackLimitCheck check(isolate);
if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
if (flag == Compiler::KEEP_EXCEPTION) {
isolate->StackOverflow();
}
return false;
}
CompilerTracer::TraceStartBaselineCompile(isolate, shared);
Handle<Code> code;
base::TimeDelta time_taken;
{
ScopedTimer timer(&time_taken);
if (!GenerateBaselineCode(isolate, shared).ToHandle(&code)) {
// TODO(leszeks): This can only fail because of an OOM. Do we want to
// report these somehow, or silently ignore them?
return false;
}
Handle<HeapObject> function_data =
handle(HeapObject::cast(shared->function_data(kAcquireLoad)), isolate);
Handle<BaselineData> baseline_data =
isolate->factory()->NewBaselineData(code, function_data);
shared->set_baseline_data(*baseline_data);
}
double time_taken_ms = time_taken.InMillisecondsF();
CompilerTracer::TraceFinishBaselineCompile(isolate, shared, time_taken_ms);
if (shared->script().IsScript()) {
Compiler::LogFunctionCompilation(
isolate, CodeEventListener::FUNCTION_TAG, shared,
handle(Script::cast(shared->script()), isolate),
Handle<AbstractCode>::cast(code), CodeKind::BASELINE, time_taken_ms);
}
return true;
}
// static
bool Compiler::CompileBaseline(Isolate* isolate, Handle<JSFunction> function,
ClearExceptionFlag flag,
......
......@@ -71,6 +71,10 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
static bool Compile(Isolate* isolate, Handle<JSFunction> function,
ClearExceptionFlag flag,
IsCompiledScope* is_compiled_scope);
static bool CompileSharedWithBaseline(Isolate* isolate,
Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag,
IsCompiledScope* is_compiled_scope);
static bool CompileBaseline(Isolate* isolate, Handle<JSFunction> function,
ClearExceptionFlag flag,
IsCompiledScope* is_compiled_scope);
......
......@@ -23,6 +23,7 @@
#include "src/base/platform/platform.h"
#include "src/base/sys-info.h"
#include "src/base/utils/random-number-generator.h"
#include "src/baseline/baseline-batch-compiler.h"
#include "src/bigint/bigint.h"
#include "src/builtins/builtins-promise.h"
#include "src/builtins/constants-table-builder.h"
......@@ -3169,6 +3170,9 @@ void Isolate::Deinit() {
delete compiler_dispatcher_;
compiler_dispatcher_ = nullptr;
delete baseline_batch_compiler_;
baseline_batch_compiler_ = nullptr;
// This stops cancelable tasks (i.e. concurrent marking tasks)
cancelable_task_manager()->CancelAndWait();
......@@ -3629,6 +3633,7 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data,
compiler_dispatcher_ =
new CompilerDispatcher(this, V8::GetCurrentPlatform(), FLAG_stack_size);
baseline_batch_compiler_ = new baseline::BaselineBatchCompiler(this);
// Enable logging before setting up the heap
logger_->SetUp(this);
......
......@@ -120,6 +120,10 @@ struct ManagedPtrDestructor;
template <StateTag Tag>
class VMState;
namespace baseline {
class BaselineBatchCompiler;
} // namespace baseline
namespace interpreter {
class Interpreter;
} // namespace interpreter
......@@ -1597,6 +1601,10 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
return compiler_dispatcher_;
}
baseline::BaselineBatchCompiler* baseline_batch_compiler() const {
return baseline_batch_compiler_;
}
bool IsInAnyContext(Object object, uint32_t index);
void ClearKeptObjects();
......@@ -2050,6 +2058,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
Zone* compiler_zone_ = nullptr;
CompilerDispatcher* compiler_dispatcher_ = nullptr;
baseline::BaselineBatchCompiler* baseline_batch_compiler_ = nullptr;
using InterruptEntry = std::pair<InterruptCallback, void*>;
std::queue<InterruptEntry> api_interrupts_queue_;
......
......@@ -484,6 +484,7 @@ DEFINE_WEAK_IMPLICATION(future, super_ic)
DEFINE_WEAK_IMPLICATION(future, turbo_inline_js_wasm_calls)
#if ENABLE_SPARKPLUG
DEFINE_WEAK_IMPLICATION(future, sparkplug)
DEFINE_WEAK_IMPLICATION(future, baseline_batch_compilation)
#endif
#if V8_SHORT_BUILTIN_CALLS
DEFINE_WEAK_IMPLICATION(future, short_builtin_calls)
......@@ -665,6 +666,9 @@ DEFINE_BOOL(always_sparkplug, false, "directly tier up to Sparkplug code")
DEFINE_IMPLICATION(always_sparkplug, sparkplug)
#endif
DEFINE_STRING(sparkplug_filter, "*", "filter for Sparkplug baseline compiler")
DEFINE_BOOL(baseline_batch_compilation, false, "batch compile Sparkplug code")
DEFINE_INT(baseline_batch_compilation_threshold, 4 * KB,
"the estimated instruction size of a batch to trigger compilation")
DEFINE_BOOL(trace_baseline, false, "trace baseline compilation")
#undef FLAG
......
......@@ -749,6 +749,7 @@ CodePageCollectionMemoryModificationScope::
if (heap_->write_protect_code_memory() &&
!heap_->code_space_memory_modification_scope_depth()) {
heap_->EnableUnprotectedMemoryChunksRegistry();
heap_->IncrementCodePageCollectionMemoryModificationScopeDepth();
}
}
......@@ -756,8 +757,11 @@ CodePageCollectionMemoryModificationScope::
~CodePageCollectionMemoryModificationScope() {
if (heap_->write_protect_code_memory() &&
!heap_->code_space_memory_modification_scope_depth()) {
heap_->ProtectUnprotectedMemoryChunks();
heap_->DisableUnprotectedMemoryChunksRegistry();
heap_->DecrementCodePageCollectionMemoryModificationScopeDepth();
if (heap_->code_page_collection_memory_modification_scope_depth() == 0) {
heap_->ProtectUnprotectedMemoryChunks();
heap_->DisableUnprotectedMemoryChunksRegistry();
}
}
}
......
......@@ -665,6 +665,18 @@ class Heap {
return unprotected_memory_chunks_registry_enabled_;
}
void IncrementCodePageCollectionMemoryModificationScopeDepth() {
code_page_collection_memory_modification_scope_depth_++;
}
void DecrementCodePageCollectionMemoryModificationScopeDepth() {
code_page_collection_memory_modification_scope_depth_--;
}
uintptr_t code_page_collection_memory_modification_scope_depth() {
return code_page_collection_memory_modification_scope_depth_;
}
inline HeapState gc_state() const {
return gc_state_.load(std::memory_order_relaxed);
}
......@@ -2196,6 +2208,9 @@ class Heap {
// Holds the number of open CodeSpaceMemoryModificationScopes.
uintptr_t code_space_memory_modification_scope_depth_ = 0;
// Holds the number of open CodePageCollectionMemoryModificationScopes.
uintptr_t code_page_collection_memory_modification_scope_depth_ = 0;
std::atomic<HeapState> gc_state_{NOT_IN_GC};
int gc_post_processing_depth_ = 0;
......
......@@ -344,13 +344,17 @@ RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterruptFromBytecode) {
// a non zero invocation count so we can inline functions.
function->feedback_vector().set_invocation_count(1);
if (FLAG_sparkplug) {
CompilationMode compilation_mode =
FLAG_baseline_batch_compilation ? kCompileBatch : kCompileImmediate;
if (V8_LIKELY(FLAG_use_osr)) {
JavaScriptFrameIterator it(isolate);
DCHECK(it.frame()->is_unoptimized());
UnoptimizedFrame* frame = UnoptimizedFrame::cast(it.frame());
OSRInterpreterFrameToBaseline(isolate, function, frame);
OSRInterpreterFrameToBaseline(isolate, function, frame,
compilation_mode);
} else {
OSRInterpreterFrameToBaseline(isolate, function, nullptr);
OSRInterpreterFrameToBaseline(isolate, function, nullptr,
compilation_mode);
}
}
return ReadOnlyRoots(isolate).undefined_value();
......
......@@ -505,7 +505,7 @@ RUNTIME_FUNCTION(Runtime_BaselineOsr) {
}
UnoptimizedFrame* frame = UnoptimizedFrame::cast(it.frame());
OSRInterpreterFrameToBaseline(isolate, function, frame);
OSRInterpreterFrameToBaseline(isolate, function, frame, kCompileImmediate);
return ReadOnlyRoots(isolate).undefined_value();
}
......
......@@ -13877,6 +13877,8 @@ UNINITIALIZED_TEST(SetJitCodeEventHandler) {
i::FLAG_stress_compaction = true;
i::FLAG_incremental_marking = false;
i::FLAG_stress_concurrent_allocation = false; // For SimulateFullSpace.
// Batch compilation can cause different owning spaces for foo and bar.
i::FLAG_baseline_batch_compilation = false;
if (i::FLAG_never_compact) return;
const char* script =
"function bar() {"
// Copyright 2021 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.
// Flags: --sparkplug --no-always-sparkplug --sparkplug-filter="-"
// Flags: --allow-natives-syntax --expose-gc
// Flags: --baseline-batch-compilation --baseline-batch-compilation-threshold=200
// Basic test
(function() {
// Bytecode length 24 -> estimated instruction size 120 - 168.
function test1 (a,b) {
return (a + b + 11) * 42 / a % b;
}
// Bytecode length 24 -> estimated instruction size 120 - 168.
function test2 (a,b) {
return (a + b + 11) * 42 / a % b;
}
%NeverOptimizeFunction(test1);
// Trigger bytecode budget interrupt for test1.
for (let i=1; i<10000; ++i) {
test1(i,4711);
}
// Shouldn't be compiled because of batch compilation.
assertFalse(isBaseline(test1));
%NeverOptimizeFunction(test2);
// Trigger bytecode budget interrupt for test2.
for (let i=1; i<10000; ++i) {
test2(i,4711);
}
// Call test1 again so baseline code gets installed on the function.
test1(1,2);
// Both functions should be compiled with baseline now.
assertTrue(isBaseline(test1));
assertTrue(isBaseline(test2));
})();
// Test function weak handle.
(function() {
function test_weak (a,b) {
return (a + b + 11) * 42 / a % b;
}
function test2 (a,b) {
return (a + b + 11) * 42 / a % b;
}
for (let i=1; i<100000; ++i) {
test_weak(i,4711);
}
gc(); // GC should cause the handle to test_weak to be freed.
%NeverOptimizeFunction(test2);
// Trigger bytecode budget interrupt for test2.
for (let i=1; i<1000; ++i) {
test2(i,4711);
}
assertTrue(isBaseline(test2));
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment