[reland] Don't allocate feedback vectors and feedback metadata in lite mode

Don't allocate feedback vectors and feedback metadata in lite mode.
Also updates to skip tests that require feedback vectors.

This is a reland of
https://chromium-review.googlesource.com/c/v8/v8/+/1384087 after skipping
the failing tests.

Bug: v8:8394
Change-Id: I7766533b85a144e62996ceed8d542cdc534feeb5
Reviewed-on: https://chromium-review.googlesource.com/c/1384307
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58363}
This commit is contained in:
Mythri 2018-12-19 13:17:05 +00:00 committed by Commit Bot
parent 60e76dd8ce
commit 1ca0de67d2
19 changed files with 199 additions and 55 deletions

View File

@ -106,7 +106,7 @@ namespace internal {
V(kNotEnoughVirtualRegistersRegalloc, \
"Not enough virtual registers (regalloc)") \
V(kOptimizationDisabled, "Optimization disabled") \
V(kOptimizationDisabledForTest, "Optimization disabled for test")
V(kNeverOptimize, "Optimization is always disabled")
#define ERROR_MESSAGES_CONSTANTS(C, T) C,
enum class BailoutReason : uint8_t {

View File

@ -356,12 +356,18 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
DCHECK(!compilation_info->has_asm_wasm_data());
DCHECK(!shared_info->HasFeedbackMetadata());
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
InstallBytecodeArray(compilation_info->bytecode_array(), shared_info,
parse_info, isolate);
shared_info->set_feedback_metadata(*feedback_metadata);
if (FLAG_lite_mode) {
// Clear the feedback metadata field. In lite mode we don't need feedback
// metadata since we never allocate feedback vectors.
shared_info->set_raw_outer_scope_info_or_feedback_metadata(
HeapObjectPtr::cast(ReadOnlyRoots(isolate).undefined_value()));
} else {
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
shared_info->set_feedback_metadata(*feedback_metadata);
}
} else {
DCHECK(compilation_info->has_asm_wasm_data());
shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data());
@ -739,6 +745,11 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
function->ClearOptimizationMarker();
}
if (shared->optimization_disabled() &&
shared->disable_optimization_reason() == BailoutReason::kNeverOptimize) {
return MaybeHandle<Code>();
}
if (isolate->debug()->needs_check_on_function_call()) {
// Do not optimize when debugger needs to hook into every call.
return MaybeHandle<Code>();
@ -781,15 +792,6 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
return MaybeHandle<Code>();
}
// Do not use TurboFan when %NeverOptimizeFunction was applied.
if (shared->optimization_disabled() &&
shared->disable_optimization_reason() ==
BailoutReason::kOptimizationDisabledForTest) {
compilation_info->AbortOptimization(
BailoutReason::kOptimizationDisabledForTest);
return MaybeHandle<Code>();
}
// Do not use TurboFan if optimization is disabled or function doesn't pass
// turbo_filter.
if (!FLAG_opt || !shared->PassesFilter(FLAG_turbo_filter)) {

View File

@ -46,7 +46,8 @@ std::unique_ptr<TypeProfile> TypeProfile::Collect(Isolate* isolate) {
if (script != info->script()) {
continue;
}
if (info->feedback_metadata()->is_empty() ||
if (!info->HasFeedbackMetadata() ||
info->feedback_metadata()->is_empty() ||
!info->feedback_metadata()->HasTypeProfileSlot()) {
continue;
}

View File

@ -3664,6 +3664,12 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_raw_function_token_offset(0);
// All flags default to false or 0.
share->set_flags(0);
// For lite mode disable optimization.
if (FLAG_lite_mode) {
share->set_flags(
SharedFunctionInfo::DisabledOptimizationReasonBits::encode(
BailoutReason::kNeverOptimize));
}
share->CalculateConstructAsBuiltin();
share->set_kind(kind);

View File

@ -1102,8 +1102,7 @@ void SharedFunctionInfo::SharedFunctionInfoVerify(Isolate* isolate) {
CHECK(!HasFeedbackMetadata());
CHECK(outer_scope_info()->IsScopeInfo() ||
outer_scope_info()->IsTheHole(isolate));
} else if (HasBytecodeArray()) {
CHECK(HasFeedbackMetadata());
} else if (HasBytecodeArray() && HasFeedbackMetadata()) {
CHECK(feedback_metadata()->IsFeedbackMetadata());
}

View File

@ -12714,7 +12714,9 @@ void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) {
Isolate* const isolate = function->GetIsolate();
DCHECK(function->shared()->is_compiled());
if (!function->has_feedback_vector()) {
DCHECK(FLAG_lite_mode || function->shared()->HasFeedbackMetadata());
if (!function->has_feedback_vector() &&
function->shared()->HasFeedbackMetadata()) {
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
if (!shared->HasAsmWasmData()) {
DCHECK(function->shared()->HasBytecodeArray());

View File

@ -233,6 +233,12 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
return ReadOnlyRoots(isolate).undefined_value();
}
if (function->shared()->optimization_disabled() &&
function->shared()->disable_optimization_reason() ==
BailoutReason::kNeverOptimize) {
return ReadOnlyRoots(isolate).undefined_value();
}
// If the function is already optimized, just return.
if (function->IsOptimized() || function->shared()->HasAsmWasmData()) {
return ReadOnlyRoots(isolate).undefined_value();
@ -296,6 +302,12 @@ RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
// If the function is already optimized, just return.
if (function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
if (function->shared()->optimization_disabled() &&
function->shared()->disable_optimization_reason() ==
BailoutReason::kNeverOptimize) {
return ReadOnlyRoots(isolate).undefined_value();
}
// Ensure that the function is marked for non-concurrent optimization, so that
// subsequent runs don't also optimize.
if (!function->HasOptimizedCode()) {
@ -328,8 +340,7 @@ RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
return ReadOnlyRoots(isolate).undefined_value();
}
Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
function->shared()->DisableOptimization(
BailoutReason::kOptimizationDisabledForTest);
function->shared()->DisableOptimization(BailoutReason::kNeverOptimize);
return ReadOnlyRoots(isolate).undefined_value();
}

View File

@ -34,7 +34,7 @@
# This test is so detailed in it's look at the literals array, I can't
# maintain it until the CL is done.
'test-heap-profiler/AllocationSitesAreVisible': [FAIL],
'test-heap-profiler/AllocationSitesAreVisible': [FAIL, ['lite_mode == True', SKIP]],
# These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed.
@ -464,4 +464,49 @@
'test-unwinder/*': [SKIP]
}],
##############################################################################
['lite_mode == True', {
# TODO(8394): First execution events don't work in lite_mode. Enable this after
# we fix the lite mode to track the first execution.
'test-log/LogFunctionEvents': [SKIP],
# Skip tests for weak references in feedback vector.
'test-weak-references/WeakReferencesBasic': [SKIP],
'test-weak-references/WeakReferencesOldToOld': [SKIP],
'test-weak-references/WeakReferencesOldToNew': [SKIP],
'test-weak-references/WeakReferencesOldToNewScavenged': [SKIP],
'test-weak-references/WeakReferencesOldToCleared': [SKIP],
'test-weak-references/ObjectMovesBeforeClearingWeakField': [SKIP],
'test-weak-references/ObjectWithWeakFieldDies': [SKIP],
'test-weak-references/ObjectWithWeakReferencePromoted': [SKIP],
'test-weak-references/ObjectWithClearedWeakReferencePromoted': [SKIP],
'test-weak-references/WeakReferenceWriteBarrier': [SKIP],
'test-heap-profiler/WeakReference': [SKIP],
# Skip compiler tests that need optimizer to be enabled.
'test-run-intrinsics/*': [SKIP],
'test-run-jsbranches/*': [SKIP],
'test-run-jscalls/*': [SKIP],
'test-run-jsexceptions/*': [SKIP],
'test-run-jsobjects/*': [SKIP],
'test-run-jsops/*': [SKIP],
'test-run-load-store/*': [SKIP],
'test-run-machops/*': [SKIP],
'test-run-native-calls/*': [SKIP],
'test-run-retpoline/*': [SKIP],
'test-run-stackcheck/*': [SKIP],
'test-run-tail-calls/*': [SKIP],
'test-run-unwinding-info/*': [SKIP],
'test-run-variables/*': [SKIP],
'test-run-bytecode-graph-builder/*': [SKIP],
'test-run-deopt/*': [SKIP],
'test-js-context-specialization/*': [SKIP],
'test-code-assembler/*': [SKIP],
'test-code-stub-assembler/*': [SKIP],
'test-accessor-assembler/*': [SKIP],
'test-torque/*': [SKIP],
'test-code-generator/*': [SKIP],
}],
]

View File

@ -3250,6 +3250,7 @@ static void CheckVectorIC(Handle<JSFunction> f, int slot_index,
}
TEST(IncrementalMarkingPreservesMonomorphicConstructor) {
if (FLAG_lite_mode) return;
if (!FLAG_incremental_marking) return;
if (FLAG_always_opt) return;
CcTest::InitializeVM();
@ -3813,6 +3814,8 @@ void CheckNumberOfAllocations(Heap* heap, const char* source,
}
TEST(AllocationSiteCreation) {
// No feedback vectors and hence no allocation sites.
if (FLAG_lite_mode) return;
FLAG_always_opt = false;
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
@ -4275,6 +4278,7 @@ static void ClearWeakIC(
TEST(WeakFunctionInConstructor) {
if (FLAG_lite_mode) return;
if (FLAG_always_opt) return;
FLAG_stress_compaction = false;
FLAG_stress_incremental_marking = false;

View File

@ -30,8 +30,10 @@ InterpreterTester::InterpreterTester(
InterpreterTester::InterpreterTester(
Isolate* isolate, Handle<BytecodeArray> bytecode,
MaybeHandle<FeedbackMetadata> feedback_metadata, const char* filter)
: InterpreterTester(isolate, nullptr, bytecode, feedback_metadata, filter) {
}
: InterpreterTester(
isolate, nullptr, bytecode,
FLAG_lite_mode ? MaybeHandle<FeedbackMetadata>() : feedback_metadata,
filter) {}
InterpreterTester::InterpreterTester(Isolate* isolate, const char* source,
const char* filter)

View File

@ -89,6 +89,8 @@ class InterpreterTester {
return RegisterList(first_reg_index, register_count);
}
inline bool HasFeedbackMetadata() { return !feedback_metadata_.is_null(); }
private:
Isolate* isolate_;
const char* source_;
@ -122,7 +124,7 @@ class InterpreterTester {
if (!bytecode_.is_null()) {
function->shared()->set_function_data(*bytecode_.ToHandleChecked());
}
if (!feedback_metadata_.is_null()) {
if (HasFeedbackMetadata()) {
function->set_raw_feedback_cell(isolate_->heap()->many_closures_cell());
// Set the raw feedback metadata to circumvent checks that we are not
// overwriting existing metadata.

View File

@ -422,9 +422,11 @@ TEST(InterpreterBinaryOpsBigInt) {
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->IsBigInt());
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(BinaryOperationFeedback::kBigInt, feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(BinaryOperationFeedback::kBigInt, feedback->ToSmi().value());
}
}
}
}
@ -542,9 +544,11 @@ TEST(InterpreterStringAdd) {
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*test_cases[i].expected_value));
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(test_cases[i].expected_feedback, feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(test_cases[i].expected_feedback, feedback->ToSmi().value());
}
}
}
@ -623,6 +627,8 @@ TEST(InterpreterParameter8) {
}
TEST(InterpreterBinaryOpTypeFeedback) {
if (FLAG_lite_mode) return;
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
Zone* zone = handles.main_zone();
@ -755,6 +761,8 @@ TEST(InterpreterBinaryOpTypeFeedback) {
}
TEST(InterpreterBinaryOpSmiTypeFeedback) {
if (FLAG_lite_mode) return;
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
Zone* zone = handles.main_zone();
@ -861,6 +869,8 @@ TEST(InterpreterBinaryOpSmiTypeFeedback) {
}
TEST(InterpreterUnaryOpFeedback) {
if (FLAG_lite_mode) return;
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
Zone* zone = handles.main_zone();
@ -947,6 +957,8 @@ TEST(InterpreterUnaryOpFeedback) {
}
TEST(InterpreterBitwiseTypeFeedback) {
if (FLAG_lite_mode) return;
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
Zone* zone = handles.main_zone();
@ -1814,10 +1826,12 @@ TEST(InterpreterSmiComparisons) {
CHECK(return_value->IsBoolean());
CHECK_EQ(return_value->BooleanValue(isolate),
CompareC(comparison, inputs[i], inputs[j]));
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(CompareOperationFeedback::kSignedSmall,
feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(CompareOperationFeedback::kSignedSmall,
feedback->ToSmi().value());
}
}
}
}
@ -1863,9 +1877,12 @@ TEST(InterpreterHeapNumberComparisons) {
CHECK(return_value->IsBoolean());
CHECK_EQ(return_value->BooleanValue(isolate),
CompareC(comparison, inputs[i], inputs[j]));
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(CompareOperationFeedback::kNumber, feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(CompareOperationFeedback::kNumber,
feedback->ToSmi().value());
}
}
}
}
@ -1905,9 +1922,12 @@ TEST(InterpreterBigIntComparisons) {
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->IsBoolean());
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(CompareOperationFeedback::kBigInt, feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
CHECK_EQ(CompareOperationFeedback::kBigInt,
feedback->ToSmi().value());
}
}
}
}
@ -1952,13 +1972,15 @@ TEST(InterpreterStringComparisons) {
CHECK(return_value->IsBoolean());
CHECK_EQ(return_value->BooleanValue(isolate),
CompareC(comparison, inputs[i], inputs[j]));
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
int const expected_feedback =
Token::IsOrderedRelationalCompareOp(comparison)
? CompareOperationFeedback::kString
: CompareOperationFeedback::kInternalizedString;
CHECK_EQ(expected_feedback, feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
int const expected_feedback =
Token::IsOrderedRelationalCompareOp(comparison)
? CompareOperationFeedback::kString
: CompareOperationFeedback::kInternalizedString;
CHECK_EQ(expected_feedback, feedback->ToSmi().value());
}
}
}
}
@ -2063,10 +2085,13 @@ TEST(InterpreterMixedComparisons) {
CHECK(return_value->IsBoolean());
CHECK_EQ(return_value->BooleanValue(isolate),
CompareC(comparison, lhs, rhs, true));
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
// Comparison with a number and string collects kAny feedback.
CHECK_EQ(CompareOperationFeedback::kAny, feedback->ToSmi().value());
if (tester.HasFeedbackMetadata()) {
MaybeObject feedback = callable.vector()->Get(slot);
CHECK(feedback->IsSmi());
// Comparison with a number and string collects kAny feedback.
CHECK_EQ(CompareOperationFeedback::kAny,
feedback->ToSmi().value());
}
}
}
}

View File

@ -338,7 +338,7 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
TEST(FeedbackVectorUnaffectedByScopeChanges) {
if (i::FLAG_always_opt || !i::FLAG_lazy) {
if (i::FLAG_always_opt || !i::FLAG_lazy || i::FLAG_lite_mode) {
return;
}
CcTest::InitializeVM();
@ -772,6 +772,7 @@ TEST(CompileFunctionInContextFunctionToString) {
}
TEST(InvocationCount) {
if (FLAG_lite_mode) return;
FLAG_allow_natives_syntax = true;
FLAG_always_opt = false;
CcTest::InitializeVM();

View File

@ -4031,6 +4031,8 @@ UNINITIALIZED_TEST(DebugSetOutOfMemoryListener) {
}
TEST(DebugCoverage) {
// Coverage needs feedback vectors.
if (i::FLAG_lite_mode) return;
i::FLAG_always_opt = false;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
@ -4084,6 +4086,8 @@ v8::debug::Coverage::ScriptData GetScriptDataAndDeleteCoverage(
} // namespace
TEST(DebugCoverageWithCoverageOutOfScope) {
// Coverage needs feedback vectors.
if (i::FLAG_lite_mode) return;
i::FLAG_always_opt = false;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
@ -4153,6 +4157,8 @@ v8::debug::Coverage::FunctionData GetFunctionDataAndDeleteCoverage(
} // namespace
TEST(DebugCoverageWithScriptDataOutOfScope) {
// Coverage needs feedback vectors.
if (i::FLAG_lite_mode) return;
i::FLAG_always_opt = false;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();

View File

@ -2447,6 +2447,8 @@ TEST(ManyLocalsInSharedContext) {
TEST(AllocationSitesAreVisible) {
if (i::FLAG_lite_mode) return;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
@ -2690,7 +2692,9 @@ TEST(TrackHeapAllocationsWithInlining) {
const char* names[] = {"", "start", "f_0_0"};
AllocationTraceNode* node = FindNode(tracker, ArrayVector(names));
CHECK(node);
CHECK_GE(node->allocation_count(), 8u);
// In lite mode, there is feedback and feedback metadata.
unsigned int num_nodes = (i::FLAG_lite_mode) ? 6 : 8;
CHECK_GE(node->allocation_count(), num_nodes);
CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
heap_profiler->StopTrackingHeapObjects();
}

View File

@ -752,7 +752,8 @@ TEST(BailoutReason) {
current = PickChild(current, "Debugger");
CHECK(const_cast<v8::CpuProfileNode*>(current));
CHECK(!strcmp("Optimization disabled for test", current->GetBailoutReason()));
CHECK(
!strcmp("Optimization is always disabled", current->GetBailoutReason()));
#endif // V8_LITE_MODE
}

View File

@ -2185,7 +2185,8 @@ static bool toplevel_test_code_event_found = false;
static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
if (event->type == v8::JitCodeEvent::CODE_ADDED &&
memcmp(event->name.str, "Script:~test", 12) == 0) {
(memcmp(event->name.str, "Script:~test", 12) == 0 ||
memcmp(event->name.str, "Script:test", 11) == 0)) {
toplevel_test_code_event_found = true;
}
}

View File

@ -34,6 +34,16 @@
'debugger/evaluate-on-call-frame-in-module': [PASS, FAIL],
}], # variant != default
['lite_mode == True', {
# Lite mode does not allocate feedback vector.
'type-profiler/type-profile-start-stop': [SKIP],
'type-profiler/type-profile': [SKIP],
'type-profiler/type-profile-with-to-string-tag': [SKIP],
'type-profiler/type-profile-with-classes': [SKIP],
'type-profiler/type-profile-disable': [SKIP]
}], # 'lite_mode == True'
##############################################################################
['(arch == arm or arch == arm64) and simulator_run', {
# Slow tests: https://crbug.com/v8/7783

View File

@ -321,6 +321,28 @@
'regress/regress-crbug-762472': [SKIP],
}], # 'gc_stress == True'
##############################################################################
['lite_mode == True', {
# Skip tests not suitable for lite_mode.
# TODO(8596): We cache the templates in the feedback vector. In lite mode
# without feedback vectors we need to implement some other mechanism to cache
# them. Enable this test after fixing it.
'es6/templates': [SKIP],
# code coverage needs feedback vectors
'code-coverage-ad-hoc': [SKIP],
'code-coverage-class-fields': [SKIP],
'code-coverage-block-noopt': [SKIP],
'code-coverage-block': [SKIP],
'code-coverage-precise': [SKIP],
# Needs feedback vector - tests for allocation sites
'array-constructor-feedback': [SKIP],
'regress/regress-trap-allocation-memento': [SKIP],
'regress/regress-4121': [SKIP],
}], # 'lite_mode == True'
##############################################################################
['byteorder == big', {
# Emscripten requires little-endian, skip all tests on big endian platforms.