transitions.cc 8.16 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/v8.h"
6

7 8 9
#include "src/objects.h"
#include "src/transitions-inl.h"
#include "src/utils.h"
10 11 12 13 14

namespace v8 {
namespace internal {


15
Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
16 17 18 19
                                                  int number_of_transitions,
                                                  int slack) {
  Handle<FixedArray> array = isolate->factory()->NewFixedArray(
      LengthFor(number_of_transitions + slack));
20
  array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
21
  array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
22
  return Handle<TransitionArray>::cast(array);
23 24 25
}


26 27 28 29 30 31
Handle<TransitionArray> TransitionArray::AllocateSimple(Isolate* isolate,
                                                        Handle<Map> target) {
  Handle<FixedArray> array =
      isolate->factory()->NewFixedArray(kSimpleTransitionSize);
  array->set(kSimpleTransitionTarget, *target);
  return Handle<TransitionArray>::cast(array);
32 33 34
}


35 36 37 38 39 40
void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
                                                        int origin_transition,
                                                        int target_transition) {
  NoIncrementalWriteBarrierSet(target_transition,
                               origin->GetKey(origin_transition),
                               origin->GetTarget(origin_transition));
41 42 43
}


44 45
Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
                                                 Handle<Name> name,
46
                                                 Handle<Map> target,
47
                                                 SimpleTransitionFlag flag) {
48
  Handle<TransitionArray> result;
49
  Isolate* isolate = name->GetIsolate();
50

51
  if (flag == SIMPLE_PROPERTY_TRANSITION) {
52
    result = AllocateSimple(isolate, target);
53
  } else {
54
    result = Allocate(isolate, 1);
55
    result->NoIncrementalWriteBarrierSet(0, *name, *target);
56
  }
57
  result->set_back_pointer_storage(map->GetBackPointer());
58 59
  return result;
}
60 61


62
Handle<TransitionArray> TransitionArray::ExtendToFullTransitionArray(
63
    Handle<Map> containing_map) {
64
  DCHECK(!containing_map->transitions()->IsFullTransitionArray());
65
  int nof = containing_map->transitions()->number_of_transitions();
66

67 68 69 70 71
  // A transition array may shrink during GC.
  Handle<TransitionArray> result = Allocate(containing_map->GetIsolate(), nof);
  DisallowHeapAllocation no_gc;
  int new_nof = containing_map->transitions()->number_of_transitions();
  if (new_nof != nof) {
72
    DCHECK(new_nof == 0);
73
    result->Shrink(ToKeyIndex(0));
74
    result->SetNumberOfTransitions(0);
75
  } else if (nof == 1) {
76
    result->NoIncrementalWriteBarrierCopyFrom(
77
        containing_map->transitions(), kSimpleTransitionIndex, 0);
78 79
  }

80 81
  result->set_back_pointer_storage(
      containing_map->transitions()->back_pointer_storage());
82 83 84 85
  return result;
}


86 87 88 89
Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
                                                Handle<Name> name,
                                                Handle<Map> target,
                                                SimpleTransitionFlag flag) {
90 91 92
  if (!map->HasTransitionArray()) {
    return TransitionArray::NewWith(map, name, target, flag);
  }
93

94
  int number_of_transitions = map->transitions()->number_of_transitions();
95
  int new_nof = number_of_transitions;
96

97 98 99
  bool is_special_transition = flag == SPECIAL_TRANSITION;
  DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
  PropertyDetails details = is_special_transition
100
                                ? PropertyDetails(NONE, DATA, 0)
101
                                : GetTargetDetails(*name, *target);
102

103 104 105 106 107
  int insertion_index = kNotFound;
  int index =
      is_special_transition
          ? map->transitions()->SearchSpecial(Symbol::cast(*name),
                                              &insertion_index)
108
          : map->transitions()->Search(details.kind(), *name,
109
                                       details.attributes(), &insertion_index);
110 111 112 113 114 115 116
  if (index == kNotFound) {
    ++new_nof;
  } else {
    insertion_index = index;
  }
  DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);

117 118 119 120 121 122
  CHECK(new_nof <= kMaxNumberOfTransitions);

  if (new_nof <= map->transitions()->number_of_transitions_storage()) {
    DisallowHeapAllocation no_gc;
    TransitionArray* array = map->transitions();

123 124
    if (index != kNotFound) {
      array->SetTarget(index, *target);
125 126 127 128
      return handle(array);
    }

    array->SetNumberOfTransitions(new_nof);
129 130 131 132
    for (index = number_of_transitions; index > insertion_index; --index) {
      Name* key = array->GetKey(index - 1);
      array->SetKey(index, key);
      array->SetTarget(index, array->GetTarget(index - 1));
133
    }
134 135
    array->SetKey(index, *name);
    array->SetTarget(index, *target);
136
    SLOW_DCHECK(array->IsSortedNoDuplicates());
137 138
    return handle(array);
  }
139

140 141 142
  Handle<TransitionArray> result = Allocate(
      map->GetIsolate(), new_nof,
      Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
143

144 145 146
  // The map's transition array may grown smaller during the allocation above as
  // it was weakly traversed, though it is guaranteed not to disappear. Trim the
  // result copy if needed, and recompute variables.
147
  DCHECK(map->HasTransitionArray());
148 149 150
  DisallowHeapAllocation no_gc;
  TransitionArray* array = map->transitions();
  if (array->number_of_transitions() != number_of_transitions) {
151
    DCHECK(array->number_of_transitions() < number_of_transitions);
152 153

    number_of_transitions = array->number_of_transitions();
154
    new_nof = number_of_transitions;
155

156
    insertion_index = kNotFound;
157 158 159
    index = is_special_transition ? map->transitions()->SearchSpecial(
                                        Symbol::cast(*name), &insertion_index)
                                  : map->transitions()->Search(
160
                                        details.kind(), *name,
161
                                        details.attributes(), &insertion_index);
162 163 164 165 166 167
    if (index == kNotFound) {
      ++new_nof;
    } else {
      insertion_index = index;
    }
    DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
168

169 170
    result->Shrink(ToKeyIndex(new_nof));
    result->SetNumberOfTransitions(new_nof);
171 172 173 174
  }

  if (array->HasPrototypeTransitions()) {
    result->SetPrototypeTransitions(array->GetPrototypeTransitions());
175 176
  }

177 178 179
  DCHECK_NE(kNotFound, insertion_index);
  for (int i = 0; i < insertion_index; ++i) {
    result->NoIncrementalWriteBarrierCopyFrom(array, i, i);
180
  }
181
  result->NoIncrementalWriteBarrierSet(insertion_index, *name, *target);
182 183
  for (int i = insertion_index; i < number_of_transitions; ++i) {
    result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1);
184 185
  }

186
  result->set_back_pointer_storage(array->back_pointer_storage());
187
  SLOW_DCHECK(result->IsSortedNoDuplicates());
188 189 190 191
  return result;
}


192
int TransitionArray::SearchDetails(int transition, PropertyKind kind,
193 194 195 196 197 198 199 200 201 202
                                   PropertyAttributes attributes,
                                   int* out_insertion_index) {
  int nof_transitions = number_of_transitions();
  DCHECK(transition < nof_transitions);
  Name* key = GetKey(transition);
  for (; transition < nof_transitions && GetKey(transition) == key;
       transition++) {
    Map* target = GetTarget(transition);
    PropertyDetails target_details = GetTargetDetails(key, target);

203
    int cmp = CompareDetails(kind, attributes, target_details.kind(),
204 205 206 207 208 209 210 211 212 213 214 215
                             target_details.attributes());
    if (cmp == 0) {
      return transition;
    } else if (cmp < 0) {
      break;
    }
  }
  if (out_insertion_index != NULL) *out_insertion_index = transition;
  return kNotFound;
}


216
int TransitionArray::Search(PropertyKind kind, Name* name,
217 218 219 220 221 222
                            PropertyAttributes attributes,
                            int* out_insertion_index) {
  int transition = SearchName(name, out_insertion_index);
  if (transition == kNotFound) {
    return kNotFound;
  }
223
  return SearchDetails(transition, kind, attributes, out_insertion_index);
224
}
225
} }  // namespace v8::internal