c22205c14e
Fix tests and AllocateObject. Hopefully addresses flaky https://github.com/dart-lang/sdk/issues/44940 Issue https://github.com/dart-lang/sdk/issues/36097 TEST=ci and standalone_2/out_of_memory_recovery_test.dart Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,pkg-mac-release-try Change-Id: Ife775f7a0bcdd343b887ba1bf912e07b2a8430c8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/188362 Commit-Queue: Alexander Aprelev <aam@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
108 lines
4.7 KiB
C++
108 lines
4.7 KiB
C++
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
// for details. 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/dart_api.h"
|
|
|
|
#include "platform/globals.h"
|
|
|
|
#include "vm/compiler/backend/slot.h"
|
|
#include "vm/compiler/compiler_state.h"
|
|
#include "vm/object.h"
|
|
#include "vm/parser.h"
|
|
#include "vm/symbols.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
// This is a regression test for b/121271056: there might be a race between
|
|
// background compiler and mutator where mutator changes guarded state of
|
|
// the field after Slot was created from it. A situation is possible where we
|
|
// have a clone of a field with its guarded state set to unknown, however
|
|
// Slot::Get for this field returns a Slot created from the previous clone of
|
|
// the same field with a known guarded state. In this case we must add *old*
|
|
// clone from which the Slot was created to guarded fields and not the new
|
|
// clone, because new clone has no guarded state to begin with and thus
|
|
// ParsedFunction::AddToGuardedFields(...) would simply ignore it.
|
|
// Such slots with inconsistent guarded state that are not in the current
|
|
// list of guarded fields arise due to unsuccessful inlining attempts.
|
|
// If we built and discard the graph, then guarded fields associated with
|
|
// that graph are also discarded. However the slot itself stays behind in
|
|
// the global cache.
|
|
// Adding old clone would lead to correct rejection of the compilation
|
|
// attempt because Slot type information is different from the current guarded
|
|
// state of the field.
|
|
TEST_CASE(SlotFromGuardedField) {
|
|
if (!FLAG_use_field_guards) {
|
|
return;
|
|
}
|
|
|
|
TransitionNativeToVM transition(thread);
|
|
Zone* zone = thread->zone();
|
|
|
|
// Setup: create dummy class, function and a field.
|
|
const Class& dummy_class = Class::Handle(Class::New(
|
|
Library::Handle(), String::Handle(Symbols::New(thread, "DummyClass")),
|
|
Script::Handle(), TokenPosition::kNoSource));
|
|
dummy_class.set_is_synthesized_class_unsafe();
|
|
|
|
const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
|
|
const Function& dummy_function = Function::ZoneHandle(
|
|
Function::New(signature, String::Handle(Symbols::New(thread, "foo")),
|
|
UntaggedFunction::kRegularFunction, false, false, false,
|
|
false, false, dummy_class, TokenPosition::kMinSource));
|
|
|
|
const Field& field = Field::Handle(
|
|
Field::New(String::Handle(Symbols::New(thread, "field")),
|
|
/*is_static=*/false, /*is_final=*/false, /*is_const=*/false,
|
|
/*is_reflectable=*/true, /*is_late=*/false, dummy_class,
|
|
Object::dynamic_type(), TokenPosition::kMinSource,
|
|
TokenPosition::kMinSource));
|
|
|
|
// Set non-trivial guarded state on the field.
|
|
field.set_guarded_cid_unsafe(kSmiCid);
|
|
field.set_is_nullable_unsafe(false);
|
|
|
|
// Enter compiler state.
|
|
CompilerState compiler_state(thread, /*is_aot=*/false,
|
|
/*is_optimizing=*/true);
|
|
|
|
const Field& field_clone_1 = Field::ZoneHandle(field.CloneFromOriginal());
|
|
const Field& field_clone_2 = Field::ZoneHandle(field.CloneFromOriginal());
|
|
|
|
// Check that Slot::Get() returns correctly canonicalized and configured
|
|
// slot that matches properties of the field.
|
|
ParsedFunction* parsed_function =
|
|
new (zone) ParsedFunction(thread, dummy_function);
|
|
const Slot& slot1 = Slot::Get(field_clone_1, parsed_function);
|
|
const Slot& slot2 = Slot::Get(field_clone_2, parsed_function);
|
|
EXPECT_EQ(&slot1, &slot2);
|
|
EXPECT(slot1.is_guarded_field());
|
|
EXPECT(!slot1.is_nullable());
|
|
EXPECT_EQ(kSmiCid, slot1.nullable_cid());
|
|
|
|
// Check that the field was added (once) to the list of guarded fields.
|
|
EXPECT_EQ(1, parsed_function->guarded_fields()->length());
|
|
EXPECT_EQ(parsed_function->guarded_fields()->At(0)->ptr(),
|
|
field_clone_1.ptr());
|
|
|
|
// Change the guarded state of the field to "unknown" - emulating concurrent
|
|
// modification of the guarded state in mutator) and create a new clone of
|
|
// the field.
|
|
field.set_guarded_cid_unsafe(kDynamicCid);
|
|
field.set_is_nullable_unsafe(true);
|
|
const Field& field_clone_3 = Field::ZoneHandle(field.CloneFromOriginal());
|
|
|
|
// Slot::Get must return the same slot and add the field from which it
|
|
// was created to the guarded fields list.
|
|
ParsedFunction* parsed_function2 =
|
|
new (zone) ParsedFunction(thread, dummy_function);
|
|
const Slot& slot3 = Slot::Get(field_clone_3, parsed_function2);
|
|
EXPECT_EQ(&slot1, &slot3);
|
|
EXPECT_EQ(1, parsed_function2->guarded_fields()->length());
|
|
EXPECT_EQ(parsed_function2->guarded_fields()->At(0)->ptr(),
|
|
field_clone_1.ptr());
|
|
}
|
|
|
|
} // namespace dart
|