transitions-inl.h 12.6 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 9
#include "src/objects/fixed-array-inl.h"
#include "src/objects/maybe-object-inl.h"
10
#include "src/objects/slots.h"
11
#include "src/objects/smi.h"
12
#include "src/objects/transitions.h"
13

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

17 18 19
namespace v8 {
namespace internal {

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// static
TransitionArray TransitionsAccessor::GetTransitionArray(
    Isolate* isolate, MaybeObject raw_transitions) {
  DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, raw_transitions));
  USE(isolate);
  return TransitionArray::cast(raw_transitions.GetHeapObjectAssumeStrong());
}

// static
TransitionArray TransitionsAccessor::GetTransitionArray(Isolate* isolate,
                                                        Handle<Map> map) {
  MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
  return GetTransitionArray(isolate, raw_transitions);
}

35
TransitionArray TransitionsAccessor::transitions() {
36
  return GetTransitionArray(isolate_, raw_transitions_);
37
}
38

39 40
OBJECT_CONSTRUCTORS_IMPL(TransitionArray, WeakFixedArray)

41
CAST_ACCESSOR(TransitionArray)
42

43
bool TransitionArray::HasPrototypeTransitions() {
44
  return Get(kPrototypeTransitionsIndex) != MaybeObject::FromSmi(Smi::zero());
45 46
}

47
WeakFixedArray TransitionArray::GetPrototypeTransitions() {
48
  DCHECK(HasPrototypeTransitions());  // Callers must check first.
49
  Object prototype_transitions =
50
      Get(kPrototypeTransitionsIndex)->GetHeapObjectAssumeStrong();
51
  return WeakFixedArray::cast(prototype_transitions);
52 53
}

54
HeapObjectSlot TransitionArray::GetKeySlot(int transition_number) {
55
  DCHECK(transition_number < number_of_transitions());
56
  return HeapObjectSlot(RawFieldOfElementAt(ToKeyIndex(transition_number)));
57
}
58

59
void TransitionArray::SetPrototypeTransitions(WeakFixedArray transitions) {
60
  DCHECK(transitions.IsWeakFixedArray());
61 62
  WeakFixedArray::Set(kPrototypeTransitionsIndex,
                      HeapObjectReference::Strong(transitions));
63 64
}

65
int TransitionArray::NumberOfPrototypeTransitions(
66
    WeakFixedArray proto_transitions) {
67
  if (proto_transitions.length() == 0) return 0;
68
  MaybeObject raw =
69
      proto_transitions.Get(kProtoTransitionNumberOfEntriesOffset);
70
  return raw.ToSmi().value();
71
}
72

73
Name TransitionArray::GetKey(int transition_number) {
74
  DCHECK(transition_number < number_of_transitions());
75 76
  return Name::cast(
      Get(ToKeyIndex(transition_number))->GetHeapObjectAssumeStrong());
77 78
}

79 80 81 82
Name TransitionArray::GetKey(InternalIndex index) {
  return GetKey(index.as_int());
}

83
Name TransitionsAccessor::GetKey(int transition_number) {
84 85 86
  switch (encoding()) {
    case kPrototypeInfo:
    case kUninitialized:
87
    case kMigrationTarget:
88
      UNREACHABLE();
89
      return Name();
90
    case kWeakRef: {
91
      Map map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
92
      return GetSimpleTransitionKey(map);
93
    }
94
    case kFullTransitionArray:
95
      return transitions().GetKey(transition_number);
96
  }
97
  UNREACHABLE();
98 99
}

100
void TransitionArray::SetKey(int transition_number, Name key) {
101
  DCHECK(transition_number < number_of_transitions());
102 103
  WeakFixedArray::Set(ToKeyIndex(transition_number),
                      HeapObjectReference::Strong(key));
104 105
}

106
HeapObjectSlot TransitionArray::GetTargetSlot(int transition_number) {
107
  DCHECK(transition_number < number_of_transitions());
108
  return HeapObjectSlot(RawFieldOfElementAt(ToTargetIndex(transition_number)));
109 110
}

111
// static
112
PropertyDetails TransitionsAccessor::GetTargetDetails(Name name, Map target) {
113
  DCHECK(!IsSpecialTransition(name.GetReadOnlyRoots(), name));
114
  InternalIndex descriptor = target.LastAdded();
115
  DescriptorArray descriptors = target.instance_descriptors(kRelaxedLoad);
116
  // Transitions are allowed only for the last added property.
117 118
  DCHECK(descriptors.GetKey(descriptor).Equals(name));
  return descriptors.GetDetails(descriptor);
119
}
120

121
PropertyDetails TransitionsAccessor::GetSimpleTargetDetails(Map transition) {
122
  return transition.GetLastDescriptorDetails(isolate_);
123 124 125
}

// static
126
Name TransitionsAccessor::GetSimpleTransitionKey(Map transition) {
127
  InternalIndex descriptor = transition.LastAdded();
128
  return transition.instance_descriptors().GetKey(descriptor);
129 130
}

131
// static
132
Map TransitionsAccessor::GetTargetFromRaw(MaybeObject raw) {
133
  return Map::cast(raw->GetHeapObjectAssumeWeak());
134 135
}

136
MaybeObject TransitionArray::GetRawTarget(int transition_number) {
137
  DCHECK(transition_number < number_of_transitions());
138
  return Get(ToTargetIndex(transition_number));
139
}
140

141
Map TransitionArray::GetTarget(int transition_number) {
142
  MaybeObject raw = GetRawTarget(transition_number);
143 144 145
  return TransitionsAccessor::GetTargetFromRaw(raw);
}

146
Map TransitionsAccessor::GetTarget(int transition_number) {
147 148 149
  switch (encoding()) {
    case kPrototypeInfo:
    case kUninitialized:
150
    case kMigrationTarget:
151
      UNREACHABLE();
152
      return Map();
153
    case kWeakRef:
154
      return Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
155
    case kFullTransitionArray:
156
      return transitions().GetTarget(transition_number);
157
  }
158
  UNREACHABLE();
159 160
}

161
void TransitionArray::SetRawTarget(int transition_number, MaybeObject value) {
162
  DCHECK(transition_number < number_of_transitions());
163
  DCHECK(value->IsWeak());
164
  DCHECK(value->GetHeapObjectAssumeWeak().IsMap());
165
  WeakFixedArray::Set(ToTargetIndex(transition_number), value);
166 167
}

168
bool TransitionArray::GetTargetIfExists(int transition_number, Isolate* isolate,
169
                                        Map* target) {
170
  MaybeObject raw = GetRawTarget(transition_number);
171
  HeapObject heap_object;
172 173 174 175 176
  // 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());
177
    DCHECK_EQ(raw.ToSmi(), Smi::uninitialized_deserialization_value());
178 179
    return false;
  }
180
  if (raw->GetHeapObjectIfStrong(&heap_object) &&
181
      heap_object.IsUndefined(isolate)) {
182 183 184 185 186
    return false;
  }
  *target = TransitionsAccessor::GetTargetFromRaw(raw);
  return true;
}
187

188
int TransitionArray::SearchNameForTesting(Name name, int* out_insertion_index) {
189 190 191
  return SearchName(name, out_insertion_index);
}

192 193 194 195 196
Map TransitionArray::SearchAndGetTargetForTesting(
    PropertyKind kind, Name name, PropertyAttributes attributes) {
  return SearchAndGetTarget(kind, name, attributes);
}

197 198 199
int TransitionArray::SearchSpecial(Symbol symbol, bool concurrent_search,
                                   int* out_insertion_index) {
  return SearchName(symbol, concurrent_search, out_insertion_index);
200 201
}

202 203
int TransitionArray::SearchName(Name name, bool concurrent_search,
                                int* out_insertion_index) {
204
  DCHECK(name.IsUniqueName());
205
  return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(),
206
                                       out_insertion_index, concurrent_search);
207 208
}

209
TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Map map,
210 211
                                         bool concurrent_access)
    : isolate_(isolate),
212 213 214
      map_(map),
      raw_transitions_(map.raw_transitions(isolate_, kAcquireLoad)),
      encoding_(GetEncoding(isolate_, raw_transitions_)),
215
      concurrent_access_(concurrent_access) {
216
  DCHECK_IMPLIES(encoding_ == kMigrationTarget, map_.is_deprecated());
217 218
}

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

221 222 223
// static
TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
    Isolate* isolate, MaybeObject raw_transitions) {
224
  HeapObject heap_object;
225 226 227 228 229
  if (raw_transitions->IsSmi() || raw_transitions->IsCleared()) {
    return kUninitialized;
  } else if (raw_transitions->IsWeak()) {
    return kWeakRef;
  } else if (raw_transitions->GetHeapObjectIfStrong(isolate, &heap_object)) {
230
    if (heap_object.IsTransitionArray()) {
231
      return kFullTransitionArray;
232
    } else if (heap_object.IsPrototypeInfo()) {
233
      return kPrototypeInfo;
234
    } else {
235
      DCHECK(heap_object.IsMap());
236
      return kMigrationTarget;
237 238 239 240
    }
  } else {
    UNREACHABLE();
  }
241 242
}

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
// static
TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
    Isolate* isolate, TransitionArray array) {
  return GetEncoding(isolate, MaybeObject::FromObject(array));
}

// static
TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
    Isolate* isolate, Handle<Map> map) {
  MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
  return GetEncoding(isolate, raw_transitions);
}

// static
MaybeHandle<Map> TransitionsAccessor::SearchTransition(
    Isolate* isolate, Handle<Map> map, Name name, PropertyKind kind,
    PropertyAttributes attributes) {
  Map result = TransitionsAccessor(isolate, *map)
                   .SearchTransition(name, kind, attributes);
  if (result.is_null()) return MaybeHandle<Map>();
  return MaybeHandle<Map>(result, isolate);
}

// static
MaybeHandle<Map> TransitionsAccessor::SearchSpecial(Isolate* isolate,
                                                    Handle<Map> map,
                                                    Symbol name) {
  Map result = TransitionsAccessor(isolate, *map).SearchSpecial(name);
  if (result.is_null()) return MaybeHandle<Map>();
  return MaybeHandle<Map>(result, isolate);
273 274
}

275 276
int TransitionArray::number_of_transitions() const {
  if (length() < kFirstIndex) return 0;
277
  return Get(kTransitionLengthIndex).ToSmi().value();
278 279
}

280 281
int TransitionArray::CompareKeys(Name key1, uint32_t hash1, PropertyKind kind1,
                                 PropertyAttributes attributes1, Name key2,
282
                                 uint32_t hash2, PropertyKind kind2,
283 284 285 286
                                 PropertyAttributes attributes2) {
  int cmp = CompareNames(key1, hash1, key2, hash2);
  if (cmp != 0) return cmp;

287
  return CompareDetails(kind1, attributes1, kind2, attributes2);
288 289
}

290
int TransitionArray::CompareNames(Name key1, uint32_t hash1, Name key2,
291 292 293 294 295 296 297 298 299
                                  uint32_t hash2) {
  if (key1 != key2) {
    // In case of hash collisions key1 is always "less" than key2.
    return hash1 <= hash2 ? -1 : 1;
  }

  return 0;
}

300
int TransitionArray::CompareDetails(PropertyKind kind1,
301
                                    PropertyAttributes attributes1,
302
                                    PropertyKind kind2,
303
                                    PropertyAttributes attributes2) {
304 305
  if (kind1 != kind2) {
    return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1;
306 307 308 309 310 311 312 313 314 315
  }

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

  return 0;
}

316
void TransitionArray::Set(int transition_number, Name key, MaybeObject target) {
317 318 319
  WeakFixedArray::Set(ToKeyIndex(transition_number),
                      MaybeObject::FromObject(key));
  WeakFixedArray::Set(ToTargetIndex(transition_number), target);
320 321
}

322
Name TransitionArray::GetSortedKey(int transition_number) {
323 324 325 326 327 328 329
  return GetKey(transition_number);
}

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

330 331
int TransitionArray::Capacity() {
  if (length() <= kFirstIndex) return 0;
332
  return (length() - kFirstIndex) / kEntrySize;
333
}
334

335
void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
336
  DCHECK(number_of_transitions <= Capacity());
337 338 339
  WeakFixedArray::Set(
      kTransitionLengthIndex,
      MaybeObject::FromSmi(Smi::FromInt(number_of_transitions)));
340 341
}

342
Handle<String> TransitionsAccessor::ExpectedTransitionKey() {
343
  DisallowGarbageCollection no_gc;
344 345 346 347 348 349 350 351 352
  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);
353 354
      if (details.location() != PropertyLocation::kField)
        return Handle<String>::null();
355
      DCHECK_EQ(PropertyKind::kData, details.kind());
356 357
      if (details.attributes() != NONE) return Handle<String>::null();
      Name name = GetSimpleTransitionKey(target);
358
      if (!name.IsString()) return Handle<String>::null();
359 360 361 362 363 364 365 366 367 368 369
      return handle(String::cast(name), isolate_);
    }
  }
  UNREACHABLE();
}

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

370 371
}  // namespace internal
}  // namespace v8
372

373 374
#include "src/objects/object-macros-undef.h"

375
#endif  // V8_OBJECTS_TRANSITIONS_INL_H_