transitions-inl.h 10.3 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 6
#ifndef V8_OBJECTS_TRANSITIONS_INL_H_
#define V8_OBJECTS_TRANSITIONS_INL_H_
7

8
#include "src/objects/transitions.h"
9

10
#include "src/ic/handler-configuration-inl.h"
11 12
#include "src/objects/fixed-array-inl.h"
#include "src/objects/maybe-object-inl.h"
13
#include "src/objects/slots.h"
14
#include "src/objects/smi.h"
15

16 17 18
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

19 20 21
namespace v8 {
namespace internal {

22
TransitionArray TransitionsAccessor::transitions() {
23
  DCHECK_EQ(kFullTransitionArray, encoding());
24
  return TransitionArray::cast(raw_transitions_->GetHeapObjectAssumeStrong());
25
}
26

27 28
OBJECT_CONSTRUCTORS_IMPL(TransitionArray, WeakFixedArray)

29
CAST_ACCESSOR(TransitionArray)
30

31
bool TransitionArray::HasPrototypeTransitions() {
32
  return Get(kPrototypeTransitionsIndex) != MaybeObject::FromSmi(Smi::zero());
33 34
}

35
WeakFixedArray TransitionArray::GetPrototypeTransitions() {
36
  DCHECK(HasPrototypeTransitions());  // Callers must check first.
37
  Object prototype_transitions =
38
      Get(kPrototypeTransitionsIndex)->GetHeapObjectAssumeStrong();
39
  return WeakFixedArray::cast(prototype_transitions);
40 41
}

42
HeapObjectSlot TransitionArray::GetKeySlot(int transition_number) {
43
  DCHECK(transition_number < number_of_transitions());
44
  return HeapObjectSlot(RawFieldOfElementAt(ToKeyIndex(transition_number)));
45
}
46

47
void TransitionArray::SetPrototypeTransitions(WeakFixedArray transitions) {
48
  DCHECK(transitions.IsWeakFixedArray());
49 50
  WeakFixedArray::Set(kPrototypeTransitionsIndex,
                      HeapObjectReference::Strong(transitions));
51 52
}

53
int TransitionArray::NumberOfPrototypeTransitions(
54
    WeakFixedArray proto_transitions) {
55
  if (proto_transitions.length() == 0) return 0;
56
  MaybeObject raw =
57
      proto_transitions.Get(kProtoTransitionNumberOfEntriesOffset);
58
  return raw.ToSmi().value();
59
}
60

61
Name TransitionArray::GetKey(int transition_number) {
62
  DCHECK(transition_number < number_of_transitions());
63 64
  return Name::cast(
      Get(ToKeyIndex(transition_number))->GetHeapObjectAssumeStrong());
65 66
}

67 68 69 70
Name TransitionArray::GetKey(InternalIndex index) {
  return GetKey(index.as_int());
}

71
Name TransitionsAccessor::GetKey(int transition_number) {
72 73 74
  switch (encoding()) {
    case kPrototypeInfo:
    case kUninitialized:
75
    case kMigrationTarget:
76
      UNREACHABLE();
77
      return Name();
78
    case kWeakRef: {
79
      Map map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
80
      return GetSimpleTransitionKey(map);
81
    }
82
    case kFullTransitionArray:
83
      return transitions().GetKey(transition_number);
84
  }
85
  UNREACHABLE();
86 87
}

88
void TransitionArray::SetKey(int transition_number, Name key) {
89
  DCHECK(transition_number < number_of_transitions());
90 91
  WeakFixedArray::Set(ToKeyIndex(transition_number),
                      HeapObjectReference::Strong(key));
92 93
}

94
HeapObjectSlot TransitionArray::GetTargetSlot(int transition_number) {
95
  DCHECK(transition_number < number_of_transitions());
96
  return HeapObjectSlot(RawFieldOfElementAt(ToTargetIndex(transition_number)));
97 98
}

99
// static
100
PropertyDetails TransitionsAccessor::GetTargetDetails(Name name, Map target) {
101
  DCHECK(!IsSpecialTransition(name.GetReadOnlyRoots(), name));
102
  InternalIndex descriptor = target.LastAdded();
103
  DescriptorArray descriptors = target.instance_descriptors();
104
  // Transitions are allowed only for the last added property.
105 106
  DCHECK(descriptors.GetKey(descriptor).Equals(name));
  return descriptors.GetDetails(descriptor);
107
}
108

109
PropertyDetails TransitionsAccessor::GetSimpleTargetDetails(Map transition) {
110
  return transition.GetLastDescriptorDetails(isolate_);
111 112 113
}

// static
114
Name TransitionsAccessor::GetSimpleTransitionKey(Map transition) {
115
  InternalIndex descriptor = transition.LastAdded();
116
  return transition.instance_descriptors().GetKey(descriptor);
117 118
}

119
// static
120
Map TransitionsAccessor::GetTargetFromRaw(MaybeObject raw) {
121
  return Map::cast(raw->GetHeapObjectAssumeWeak());
122 123
}

124
MaybeObject TransitionArray::GetRawTarget(int transition_number) {
125
  DCHECK(transition_number < number_of_transitions());
126
  return Get(ToTargetIndex(transition_number));
127
}
128

129
Map TransitionArray::GetTarget(int transition_number) {
130
  MaybeObject raw = GetRawTarget(transition_number);
131 132 133
  return TransitionsAccessor::GetTargetFromRaw(raw);
}

134
Map TransitionsAccessor::GetTarget(int transition_number) {
135 136 137
  switch (encoding()) {
    case kPrototypeInfo:
    case kUninitialized:
138
    case kMigrationTarget:
139
      UNREACHABLE();
140
      return Map();
141
    case kWeakRef:
142
      return Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
143
    case kFullTransitionArray:
144
      return transitions().GetTarget(transition_number);
145
  }
146
  UNREACHABLE();
147 148
}

149
void TransitionArray::SetRawTarget(int transition_number, MaybeObject value) {
150
  DCHECK(transition_number < number_of_transitions());
151
  DCHECK(value->IsWeak());
152
  DCHECK(value->GetHeapObjectAssumeWeak().IsMap());
153
  WeakFixedArray::Set(ToTargetIndex(transition_number), value);
154 155
}

156
bool TransitionArray::GetTargetIfExists(int transition_number, Isolate* isolate,
157
                                        Map* target) {
158
  MaybeObject raw = GetRawTarget(transition_number);
159
  HeapObject heap_object;
160
  if (raw->GetHeapObjectIfStrong(&heap_object) &&
161
      heap_object.IsUndefined(isolate)) {
162 163 164 165 166
    return false;
  }
  *target = TransitionsAccessor::GetTargetFromRaw(raw);
  return true;
}
167

168
int TransitionArray::SearchNameForTesting(Name name, int* out_insertion_index) {
169 170 171
  return SearchName(name, out_insertion_index);
}

172
int TransitionArray::SearchSpecial(Symbol symbol, int* out_insertion_index) {
173 174 175
  return SearchName(symbol, out_insertion_index);
}

176
int TransitionArray::SearchName(Name name, int* out_insertion_index) {
177
  DCHECK(name.IsUniqueName());
178 179
  return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(),
                                       out_insertion_index);
180 181
}

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Map map,
                                         DisallowHeapAllocation* no_gc)
    : isolate_(isolate), map_(map) {
  Initialize();
  USE(no_gc);
}

TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Handle<Map> map)
    : isolate_(isolate), map_handle_(map), map_(*map) {
  Initialize();
}

void TransitionsAccessor::Reload() {
  DCHECK(!map_handle_.is_null());
  map_ = *map_handle_;
  Initialize();
}

void TransitionsAccessor::Initialize() {
201
  raw_transitions_ = map_.raw_transitions(isolate_);
202 203 204 205 206
  HeapObject heap_object;
  if (raw_transitions_->IsSmi() || raw_transitions_->IsCleared()) {
    encoding_ = kUninitialized;
  } else if (raw_transitions_->IsWeak()) {
    encoding_ = kWeakRef;
207
  } else if (raw_transitions_->GetHeapObjectIfStrong(isolate_, &heap_object)) {
208
    if (heap_object.IsTransitionArray()) {
209
      encoding_ = kFullTransitionArray;
210
    } else if (heap_object.IsPrototypeInfo()) {
211 212
      encoding_ = kPrototypeInfo;
    } else {
213 214
      DCHECK(map_.is_deprecated());
      DCHECK(heap_object.IsMap());
215 216 217 218 219 220 221 222 223 224
      encoding_ = kMigrationTarget;
    }
  } else {
    UNREACHABLE();
  }
#if DEBUG
  needs_reload_ = false;
#endif
}

225 226
int TransitionArray::number_of_transitions() const {
  if (length() < kFirstIndex) return 0;
227
  return Get(kTransitionLengthIndex).ToSmi().value();
228 229
}

230 231
int TransitionArray::CompareKeys(Name key1, uint32_t hash1, PropertyKind kind1,
                                 PropertyAttributes attributes1, Name key2,
232
                                 uint32_t hash2, PropertyKind kind2,
233 234 235 236
                                 PropertyAttributes attributes2) {
  int cmp = CompareNames(key1, hash1, key2, hash2);
  if (cmp != 0) return cmp;

237
  return CompareDetails(kind1, attributes1, kind2, attributes2);
238 239
}

240
int TransitionArray::CompareNames(Name key1, uint32_t hash1, Name key2,
241 242 243 244 245 246 247 248 249
                                  uint32_t hash2) {
  if (key1 != key2) {
    // In case of hash collisions key1 is always "less" than key2.
    return hash1 <= hash2 ? -1 : 1;
  }

  return 0;
}

250
int TransitionArray::CompareDetails(PropertyKind kind1,
251
                                    PropertyAttributes attributes1,
252
                                    PropertyKind kind2,
253
                                    PropertyAttributes attributes2) {
254 255
  if (kind1 != kind2) {
    return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1;
256 257 258 259 260 261 262 263 264 265
  }

  if (attributes1 != attributes2) {
    return static_cast<int>(attributes1) < static_cast<int>(attributes2) ? -1
                                                                         : 1;
  }

  return 0;
}

266
void TransitionArray::Set(int transition_number, Name key, MaybeObject target) {
267 268 269
  WeakFixedArray::Set(ToKeyIndex(transition_number),
                      MaybeObject::FromObject(key));
  WeakFixedArray::Set(ToTargetIndex(transition_number), target);
270 271
}

272
Name TransitionArray::GetSortedKey(int transition_number) {
273 274 275 276 277 278 279
  return GetKey(transition_number);
}

int TransitionArray::number_of_entries() const {
  return number_of_transitions();
}

280 281
int TransitionArray::Capacity() {
  if (length() <= kFirstIndex) return 0;
282
  return (length() - kFirstIndex) / kEntrySize;
283
}
284

285
void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
286
  DCHECK(number_of_transitions <= Capacity());
287 288 289
  WeakFixedArray::Set(
      kTransitionLengthIndex,
      MaybeObject::FromSmi(Smi::FromInt(number_of_transitions)));
290 291
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
Handle<String> TransitionsAccessor::ExpectedTransitionKey() {
  DisallowHeapAllocation no_gc;
  switch (encoding()) {
    case kPrototypeInfo:
    case kUninitialized:
    case kMigrationTarget:
    case kFullTransitionArray:
      return Handle<String>::null();
    case kWeakRef: {
      Map target = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
      PropertyDetails details = GetSimpleTargetDetails(target);
      if (details.location() != kField) return Handle<String>::null();
      DCHECK_EQ(kData, details.kind());
      if (details.attributes() != NONE) return Handle<String>::null();
      Name name = GetSimpleTransitionKey(target);
307
      if (!name.IsString()) return Handle<String>::null();
308 309 310 311 312 313 314 315 316 317 318
      return handle(String::cast(name), isolate_);
    }
  }
  UNREACHABLE();
}

Handle<Map> TransitionsAccessor::ExpectedTransitionTarget() {
  DCHECK(!ExpectedTransitionKey().is_null());
  return handle(GetTarget(0), isolate_);
}

319 320
}  // namespace internal
}  // namespace v8
321

322 323
#include "src/objects/object-macros-undef.h"

324
#endif  // V8_OBJECTS_TRANSITIONS_INL_H_