chromium/v8/test/cctest/test-field-type-tracking.cc

// Copyright 2015 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 <stdlib.h>

#include <initializer_list>
#include <utility>

#include "src/base/logging.h"
#include "src/execution/execution.h"
#include "src/heap/factory-inl.h"
#include "src/objects/field-type.h"
#include "src/objects/heap-number-inl.h"
#include "src/objects/internal-index.h"
#include "src/objects/map-updater.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property-details.h"
#include "src/objects/property.h"
#include "src/objects/struct-inl.h"
#include "src/objects/transitions.h"
#include "src/utils/ostreams.h"
#include "test/cctest/cctest.h"

namespace v8 {
namespace internal {
namespace compiler {
namespace test_field_type_tracking {

// TODO(ishell): fix this once TransitionToPrototype stops generalizing
// all field representations (similar to crbug/448711 where elements kind
// and observed transitions caused generalization of all fields).
const bool IS_PROTO_TRANS_ISSUE_FIXED =;

// TODO(ishell): fix this once TransitionToAccessorProperty is able to always
// keep map in fast mode.
const bool IS_ACCESSOR_FIELD_SUPPORTED =;

// Number of properties used in the tests.
const int kPropCount =;

enum ChangeAlertMechanism {};

//
// Helper functions.
//

static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
                                               bool with_setter) {}

// Check cached migration target map after Map::Update() and Map::TryUpdate()
static void CheckMigrationTarget(Isolate* isolate, Tagged<Map> old_map,
                                 Tagged<Map> new_map) {}

class Expectations {};


////////////////////////////////////////////////////////////////////////////////
// A set of tests for property reconfiguration that makes new transition tree
// branch.
//

namespace {

Handle<Map> ReconfigureProperty(Isolate* isolate, Handle<Map> map,
                                InternalIndex modify_index,
                                PropertyKind new_kind,
                                PropertyAttributes new_attributes,
                                Representation new_representation,
                                Handle<FieldType> new_field_type) {}

}  // namespace

TEST(ReconfigureAccessorToNonExistingDataField) {}


// This test checks that the LookupIterator machinery involved in
// JSObject::SetOwnPropertyIgnoreAttributes() does not try to migrate object
// to a map with a property with None representation.
TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {}


////////////////////////////////////////////////////////////////////////////////
// A set of tests for field generalization case.
//

namespace {

// <Constness, Representation, FieldType> data.
struct CRFTData {};

Handle<Code> CreateDummyOptimizedCode(Isolate* isolate) {}

static void CheckCodeObjectForDeopt(const CRFTData& from,
                                    const CRFTData& expected,
                                    DirectHandle<Code> code_field_type,
                                    DirectHandle<Code> code_field_repr,
                                    Handle<Code> code_field_const,
                                    bool expected_deopt) {}

// This test ensures that field generalization at |property_index| is done
// correctly independently of the fact that the |map| is detached from
// transition tree or not.
//
//  {} - p0 - p1 - p2: |detach_point_map|
//                  |
//                  X - detached at |detach_property_at_index|
//                  |
//                  + - p3 - p4: |map|
//
// Detaching does not happen if |detach_property_at_index| is -1.
//
void TestGeneralizeField(int detach_property_at_index, int property_index,
                         const CRFTData& from, const CRFTData& to,
                         const CRFTData& expected,
                         ChangeAlertMechanism expected_alert) {}

void TestGeneralizeField(const CRFTData& from, const CRFTData& to,
                         const CRFTData& expected,
                         ChangeAlertMechanism expected_alert) {}

}  // namespace

TEST(GeneralizeSmiFieldToDouble) {}

TEST(GeneralizeSmiFieldToTagged) {}

TEST(GeneralizeDoubleFieldToTagged) {}

TEST(GeneralizeHeapObjectFieldToTagged) {}

TEST(GeneralizeHeapObjectFieldToHeapObject) {}

TEST(GeneralizeNoneFieldToSmi) {}

TEST(GeneralizeNoneFieldToDouble) {}

TEST(GeneralizeNoneFieldToHeapObject) {}

TEST(GeneralizeNoneFieldToTagged) {}


////////////////////////////////////////////////////////////////////////////////
// A set of tests for field generalization case with kAccessor properties.
//

TEST(GeneralizeFieldWithAccessorProperties) {}

////////////////////////////////////////////////////////////////////////////////
// A set of tests for attribute reconfiguration case.
//

namespace {

// This test ensures that field generalization is correctly propagated from one
// branch of transition tree (|map2|) to another (|map|).
//
//             + - p2B - p3 - p4: |map2|
//             |
//  {} - p0 - p1 - p2A - p3 - p4: |map|
//
// where "p2A" and "p2B" differ only in the attributes.
//
void TestReconfigureDataFieldAttribute_GeneralizeField(
    const CRFTData& from, const CRFTData& to, const CRFTData& expected,
    ChangeAlertMechanism expected_alert) {}

}  // namespace

TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToDouble) {}

TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) {}

TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) {}

TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {}

TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) {}

// Checks that given |map| is deprecated and that it updates to given |new_map|
// which in turn should match expectations.
struct CheckDeprecated {};

// Checks that given |map| is NOT deprecated, equals to given |new_map| and
// matches expectations.
struct CheckSameMap {};

// Checks that given |map| is NOT deprecated and matches expectations.
// |new_map| is unrelated to |map|.
struct CheckUnrelated {};

// Checks that given |map| is NOT deprecated, and |new_map| is a result of going
// dictionary mode.
struct CheckNormalize {};

// This test ensures that field generalization is correctly propagated from one
// branch of transition tree (|map2|) to another (|map1|).
//
//             + - p2B - p3 - p4: |map2|
//             |
//  {} - p0 - p1: |map|
//             |
//             + - p2A - p3 - p4: |map1|
//                        |
//                        + - the property customized by the TestConfig provided
//
// where "p2A" and "p2B" differ only in the attributes.
//
template <typename TestConfig, typename Checker>
static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
    TestConfig* config, Checker* checker) {}

TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) {}

TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {}

TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {}


TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {}


TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {}


TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {}


////////////////////////////////////////////////////////////////////////////////
// A set of tests for elements kind reconfiguration case.
//

namespace {

// This test ensures that in-place field generalization is correctly propagated
// from one branch of transition tree (|map2|) to another (|map|).
//
//   + - p0 - p1 - p2A - p3 - p4: |map|
//   |
//  ek
//   |
//  {} - p0 - p1 - p2B - p3 - p4: |map2|
//
// where "p2A" and "p2B" differ only in the representation/field type.
//
static void TestReconfigureElementsKind_GeneralizeFieldInPlace(
    const CRFTData& from, const CRFTData& to, const CRFTData& expected) {}

}  // namespace

TEST(ReconfigureElementsKind_GeneralizeSmiFieldToDouble) {}

TEST(ReconfigureElementsKind_GeneralizeSmiFieldToTagged) {}

TEST(ReconfigureElementsKind_GeneralizeDoubleFieldToTagged) {}

TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {}

TEST(ReconfigureElementsKind_GeneralizeHeapObjectFieldToTagged) {}

////////////////////////////////////////////////////////////////////////////////
// A set of tests checking split map deprecation.
//

TEST(ReconfigurePropertySplitMapTransitionsOverflow) {}

////////////////////////////////////////////////////////////////////////////////
// A set of tests involving special transitions (such as elements kind
// transition, observed transition or prototype transition).
//
// This test ensures that field generalization is correctly propagated from one
// branch of transition tree (|map2|) to another (|map|).
//
//                            p4B: |map_b|
//                             ^
//                             |
//                             * - special transition
//                             |
//  {} - p0 - p1 - p2A - p3 - p4A: |map_a|
//
// where "p4A" and "p4B" are exactly the same properties.
//
// UpdateDirectionCheck::kFwd checks if updates to map_a propagate to map_b,
// whereas UpdateDirectionCheck::kBwd checks if updates to map_b propagate back
// to map_a.
//
enum class UpdateDirectionCheck {};
template <typename TestConfig>
static void TestGeneralizeFieldWithSpecialTransition(
    TestConfig* config, const CRFTData& from, const CRFTData& to,
    const CRFTData& expected, ChangeAlertMechanism expected_alert,
    UpdateDirectionCheck direction = UpdateDirectionCheck::kFwd) {}

template <typename TestConfig>
void TestMultipleElementsKindTransitions(Isolate* isolate, TestConfig* config,
                                         UpdateDirectionCheck direction) {}

TEST(ElementsKindTransitionFromMapOwningDescriptor) {}

TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {}

////////////////////////////////////////////////////////////////////////////////
// A set of tests for the prototype transition case.
//
// This test ensures that field generalization is correctly propagated across an
// UpdatePrototype transition.
//
// In the case of prototype transitions the transition tree is actually
// reshaped as:
//
//  {} - p0B - p1B - p2B - p3B - p4B: |map_b|
//  ^
//  |
//  * - prototype transition
//  |
//  {} - p0A - p1A - p2A - p3A - p4A: |map_a|
//
//  And the updates go via the MapUpdater. Thus generalizations from map_a to
//  map_b happen during UpdatePrototype, (i.e., on the transition of the next
//  object).
//
// By design updates currently only happen in forward direction, i.e., changes
// to map_a are propagated to map_b, but not the inverse.

template <typename TestConfig>
void TestMultiplePrototypeTransitions(Isolate* isolate, TestConfig* config) {}

TEST(PrototypeTransitionFromMapOwningDescriptor) {}

TEST(PrototypeTransitionFromMapNotOwningDescriptor) {}

////////////////////////////////////////////////////////////////////////////////
// A set of tests involving special transitions (such as elements kind
// transition, observed transition or prototype transition).
//
// The following legacy tests are for when
// !v8_flags.move_prototype_transitions_first

// This test ensures that field generalization is correctly propagated from one
// branch of transition tree (|map2|) to another (|map|).
//
//                            p4B: |map2|
//                             |
//                             * - special transition
//                             |
//  {} - p0 - p1 - p2A - p3 - p4A: |map|
//
// where "p4A" and "p4B" are exactly the same properties.
//
// TODO(ishell): unify this test template with
// TestReconfigureDataFieldAttribute_GeneralizeField once
// IS_PROTO_TRANS_ISSUE_FIXED and IS_NON_EQUIVALENT_TRANSITION_SUPPORTED are
// fixed.
template <typename TestConfig>
static void TestGeneralizeFieldWithSpecialTransitionLegacy(
    TestConfig* config, const CRFTData& from, const CRFTData& to,
    const CRFTData& expected, ChangeAlertMechanism expected_alert) {}

TEST(ElementsKindTransitionFromMapOwningDescriptorLegacy) {}

TEST(ElementsKindTransitionFromMapNotOwningDescriptorLegacy) {}

TEST(PrototypeTransitionFromMapOwningDescriptorLegacy) {}

TEST(PrototypeTransitionFromMapNotOwningDescriptorLegacy) {}

////////////////////////////////////////////////////////////////////////////////
// A set of tests for higher level transitioning mechanics.
//

struct TransitionToDataFieldOperator {};


struct TransitionToDataConstantOperator {};


struct TransitionToAccessorConstantOperator {};


struct ReconfigureAsDataPropertyOperator {};


struct ReconfigureAsAccessorPropertyOperator {};

// Checks that field generalization happened.
struct FieldGeneralizationChecker {};


// Checks that existing transition was taken as is.
struct SameMapChecker {};


// Checks that both |map1| and |map2| should stays non-deprecated, this is
// the case when property kind is change.
struct PropertyKindReconfigurationChecker {};


// This test transitions to various property types under different
// circumstances.
// Plan:
// 1) create a |map| with p0..p3 properties.
// 2) create |map1| by adding "p4" to |map0|.
// 3) create |map2| by transition to "p4" from |map0|.
//
//                       + - p4B: |map2|
//                       |
//  {} - p0 - p1 - pA - p3: |map|
//                       |
//                       + - p4A: |map1|
//
// where "p4A" and "p4B" differ only in the attributes.
//
template <typename TransitionOp1, typename TransitionOp2, typename Checker>
static void TestTransitionTo(TransitionOp1* transition_op1,
                             TransitionOp2* transition_op2, Checker* checker) {}

TEST(TransitionDataFieldToDataField) {}

TEST(TransitionDataConstantToSameDataConstant) {}


TEST(TransitionDataConstantToAnotherDataConstant) {}


TEST(TransitionDataConstantToDataField) {}


TEST(TransitionAccessorConstantToSameAccessorConstant) {}

// TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported.
// TEST(TransitionAccessorConstantToAnotherAccessorConstant)

TEST(HoleyHeapNumber) {}

namespace {

template <class... Args>
MaybeHandle<Object> Call(Isolate* isolate, Handle<JSFunction> function,
                         Args... args) {}

void TestStoreToConstantField(const char* store_func_source,
                              Handle<Object> value1, Handle<Object> value2,
                              Representation expected_rep,
                              PropertyConstness expected_constness,
                              int store_repetitions) {}

void TestStoreToConstantField_PlusMinusZero(const char* store_func_source,
                                            int store_repetitions) {}

void TestStoreToConstantField_NaN(const char* store_func_source,
                                  int store_repetitions) {}

}  // namespace

TEST(StoreToConstantField_PlusMinusZero) {}

TEST(StoreToConstantField_ObjectDefineProperty) {}

TEST(StoreToConstantField_ReflectSet) {}

TEST(StoreToConstantField_StoreIC) {}

TEST(NormalizeToMigrationTarget) {}

TEST(RepresentationPredicatesAreInSync) {}

#define CHECK_SAME

TEST(CheckFitsRepresentationPredicate) {}

#undef CHECK_SAME

}  // namespace test_field_type_tracking
}  // namespace compiler
}  // namespace internal
}  // namespace v8