transitions-inl.h 11.2 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/ic/handler-configuration-inl.h"
9 10
#include "src/objects/fixed-array-inl.h"
#include "src/objects/maybe-object-inl.h"
11
#include "src/objects/slots.h"
12
#include "src/objects/smi.h"
13 14
#include "src/objects/transitions.h"
#include "src/snapshot/deserializer.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(kRelaxedLoad);
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(kRelaxedLoad).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 161 162 163 164 165 166 167
  // If the raw target is a Smi, then this TransitionArray is in the process of
  // being deserialized, and doesn't yet have an initialized entry for this
  // transition.
  if (raw.IsSmi()) {
    DCHECK(isolate->has_active_deserializer());
    DCHECK_EQ(raw.ToSmi(), Deserializer::uninitialized_field_value());
    return false;
  }
168
  if (raw->GetHeapObjectIfStrong(&heap_object) &&
169
      heap_object.IsUndefined(isolate)) {
170 171 172 173 174
    return false;
  }
  *target = TransitionsAccessor::GetTargetFromRaw(raw);
  return true;
}
175

176
int TransitionArray::SearchNameForTesting(Name name, int* out_insertion_index) {
177 178 179
  return SearchName(name, out_insertion_index);
}

180 181 182 183 184
Map TransitionArray::SearchAndGetTargetForTesting(
    PropertyKind kind, Name name, PropertyAttributes attributes) {
  return SearchAndGetTarget(kind, name, attributes);
}

185
int TransitionArray::SearchSpecial(Symbol symbol, int* out_insertion_index) {
186 187 188
  return SearchName(symbol, out_insertion_index);
}

189
int TransitionArray::SearchName(Name name, int* out_insertion_index) {
190
  DCHECK(name.IsUniqueName());
191 192 193
  // The name is taken from DescriptorArray, so it must already has a computed
  // hash.
  DCHECK(name.HasHashCode());
194 195
  return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(),
                                       out_insertion_index);
196 197
}

198 199
TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Map map,
                                         DisallowHeapAllocation* no_gc)
200
    : isolate_(isolate), map_(map), concurrent_access_(false) {
201 202 203 204
  Initialize();
  USE(no_gc);
}

205 206 207 208 209 210
TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Handle<Map> map,
                                         bool concurrent_access)
    : isolate_(isolate),
      map_handle_(map),
      map_(*map),
      concurrent_access_(concurrent_access) {
211 212 213 214 215 216 217 218 219
  Initialize();
}

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

220 221
int TransitionsAccessor::Capacity() { return transitions().Capacity(); }

222
void TransitionsAccessor::Initialize() {
223
  raw_transitions_ = map_.raw_transitions(isolate_);
224 225 226 227 228
  HeapObject heap_object;
  if (raw_transitions_->IsSmi() || raw_transitions_->IsCleared()) {
    encoding_ = kUninitialized;
  } else if (raw_transitions_->IsWeak()) {
    encoding_ = kWeakRef;
229
  } else if (raw_transitions_->GetHeapObjectIfStrong(isolate_, &heap_object)) {
230
    if (heap_object.IsTransitionArray()) {
231
      encoding_ = kFullTransitionArray;
232
    } else if (heap_object.IsPrototypeInfo()) {
233 234
      encoding_ = kPrototypeInfo;
    } else {
235 236
      DCHECK(map_.is_deprecated());
      DCHECK(heap_object.IsMap());
237 238 239 240 241 242 243 244 245 246
      encoding_ = kMigrationTarget;
    }
  } else {
    UNREACHABLE();
  }
#if DEBUG
  needs_reload_ = false;
#endif
}

247 248
int TransitionArray::number_of_transitions() const {
  if (length() < kFirstIndex) return 0;
249
  return Get(kTransitionLengthIndex).ToSmi().value();
250 251
}

252 253
int TransitionArray::CompareKeys(Name key1, uint32_t hash1, PropertyKind kind1,
                                 PropertyAttributes attributes1, Name key2,
254
                                 uint32_t hash2, PropertyKind kind2,
255 256 257 258
                                 PropertyAttributes attributes2) {
  int cmp = CompareNames(key1, hash1, key2, hash2);
  if (cmp != 0) return cmp;

259
  return CompareDetails(kind1, attributes1, kind2, attributes2);
260 261
}

262
int TransitionArray::CompareNames(Name key1, uint32_t hash1, Name key2,
263 264 265 266 267 268 269 270 271
                                  uint32_t hash2) {
  if (key1 != key2) {
    // In case of hash collisions key1 is always "less" than key2.
    return hash1 <= hash2 ? -1 : 1;
  }

  return 0;
}

272
int TransitionArray::CompareDetails(PropertyKind kind1,
273
                                    PropertyAttributes attributes1,
274
                                    PropertyKind kind2,
275
                                    PropertyAttributes attributes2) {
276 277
  if (kind1 != kind2) {
    return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1;
278 279 280 281 282 283 284 285 286 287
  }

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

  return 0;
}

288
void TransitionArray::Set(int transition_number, Name key, MaybeObject target) {
289 290 291
  WeakFixedArray::Set(ToKeyIndex(transition_number),
                      MaybeObject::FromObject(key));
  WeakFixedArray::Set(ToTargetIndex(transition_number), target);
292 293
}

294
Name TransitionArray::GetSortedKey(int transition_number) {
295 296 297 298 299 300 301
  return GetKey(transition_number);
}

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

302 303
int TransitionArray::Capacity() {
  if (length() <= kFirstIndex) return 0;
304
  return (length() - kFirstIndex) / kEntrySize;
305
}
306

307
void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
308
  DCHECK(number_of_transitions <= Capacity());
309 310 311
  WeakFixedArray::Set(
      kTransitionLengthIndex,
      MaybeObject::FromSmi(Smi::FromInt(number_of_transitions)));
312 313
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
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);
329
      if (!name.IsString()) return Handle<String>::null();
330 331 332 333 334 335 336 337 338 339 340
      return handle(String::cast(name), isolate_);
    }
  }
  UNREACHABLE();
}

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

341 342
}  // namespace internal
}  // namespace v8
343

344 345
#include "src/objects/object-macros-undef.h"

346
#endif  // V8_OBJECTS_TRANSITIONS_INL_H_