1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/objects/feedback-vector.h"
6
7 #include "src/diagnostics/code-tracer.h"
8 #include "src/heap/heap-inl.h"
9 #include "src/heap/local-factory-inl.h"
10 #include "src/ic/handler-configuration-inl.h"
11 #include "src/ic/ic-inl.h"
12 #include "src/objects/data-handler-inl.h"
13 #include "src/objects/feedback-vector-inl.h"
14 #include "src/objects/hash-table-inl.h"
15 #include "src/objects/map-inl.h"
16 #include "src/objects/object-macros.h"
17 #include "src/objects/objects.h"
18
19 namespace v8 {
20 namespace internal {
21
AddSlot(FeedbackSlotKind kind)22 FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
23 int slot = slot_count();
24 int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
25 append(kind);
26 for (int i = 1; i < entries_per_slot; i++) {
27 append(FeedbackSlotKind::kInvalid);
28 }
29 return FeedbackSlot(slot);
30 }
31
AddTypeProfileSlot()32 FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
33 FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
34 CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
35 FeedbackVector::GetIndex(slot));
36 return slot;
37 }
38
HasTypeProfileSlot() const39 bool FeedbackVectorSpec::HasTypeProfileSlot() const {
40 FeedbackSlot slot =
41 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
42 if (slot_count() <= slot.ToInt()) return false;
43 return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
44 }
45
IsPropertyNameFeedback(MaybeObject feedback)46 static bool IsPropertyNameFeedback(MaybeObject feedback) {
47 HeapObject heap_object;
48 if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
49 if (heap_object.IsString()) {
50 DCHECK(heap_object.IsInternalizedString());
51 return true;
52 }
53 if (!heap_object.IsSymbol()) return false;
54 Symbol symbol = Symbol::cast(heap_object);
55 ReadOnlyRoots roots = symbol.GetReadOnlyRoots();
56 return symbol != roots.uninitialized_symbol() &&
57 symbol != roots.megamorphic_symbol();
58 }
59
operator <<(std::ostream & os,FeedbackSlotKind kind)60 std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
61 return os << FeedbackMetadata::Kind2String(kind);
62 }
63
GetKind(FeedbackSlot slot) const64 FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
65 int index = VectorICComputer::index(0, slot.ToInt());
66 int data = get(index);
67 return VectorICComputer::decode(data, slot.ToInt());
68 }
69
SetKind(FeedbackSlot slot,FeedbackSlotKind kind)70 void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
71 int index = VectorICComputer::index(0, slot.ToInt());
72 int data = get(index);
73 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
74 set(index, new_data);
75 }
76
77 // static
78 template <typename LocalIsolate>
New(LocalIsolate * isolate,const FeedbackVectorSpec * spec)79 Handle<FeedbackMetadata> FeedbackMetadata::New(LocalIsolate* isolate,
80 const FeedbackVectorSpec* spec) {
81 auto* factory = isolate->factory();
82
83 const int slot_count = spec == nullptr ? 0 : spec->slot_count();
84 const int create_closure_slot_count =
85 spec == nullptr ? 0 : spec->create_closure_slot_count();
86 if (slot_count == 0 && create_closure_slot_count == 0) {
87 return factory->empty_feedback_metadata();
88 }
89 #ifdef DEBUG
90 for (int i = 0; i < slot_count;) {
91 DCHECK(spec);
92 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
93 int entry_size = FeedbackMetadata::GetSlotSize(kind);
94 for (int j = 1; j < entry_size; j++) {
95 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
96 DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
97 }
98 i += entry_size;
99 }
100 #endif
101
102 Handle<FeedbackMetadata> metadata =
103 factory->NewFeedbackMetadata(slot_count, create_closure_slot_count);
104
105 // Initialize the slots. The raw data section has already been pre-zeroed in
106 // NewFeedbackMetadata.
107 for (int i = 0; i < slot_count; i++) {
108 DCHECK(spec);
109 FeedbackSlot slot(i);
110 FeedbackSlotKind kind = spec->GetKind(slot);
111 metadata->SetKind(slot, kind);
112 }
113
114 return metadata;
115 }
116
117 template Handle<FeedbackMetadata> FeedbackMetadata::New(
118 Isolate* isolate, const FeedbackVectorSpec* spec);
119 template Handle<FeedbackMetadata> FeedbackMetadata::New(
120 LocalIsolate* isolate, const FeedbackVectorSpec* spec);
121
SpecDiffersFrom(const FeedbackVectorSpec * other_spec) const122 bool FeedbackMetadata::SpecDiffersFrom(
123 const FeedbackVectorSpec* other_spec) const {
124 if (other_spec->slot_count() != slot_count()) {
125 return true;
126 }
127
128 int slots = slot_count();
129 for (int i = 0; i < slots;) {
130 FeedbackSlot slot(i);
131 FeedbackSlotKind kind = GetKind(slot);
132 int entry_size = FeedbackMetadata::GetSlotSize(kind);
133
134 if (kind != other_spec->GetKind(slot)) {
135 return true;
136 }
137 i += entry_size;
138 }
139 return false;
140 }
141
Kind2String(FeedbackSlotKind kind)142 const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
143 switch (kind) {
144 case FeedbackSlotKind::kInvalid:
145 return "Invalid";
146 case FeedbackSlotKind::kCall:
147 return "Call";
148 case FeedbackSlotKind::kLoadProperty:
149 return "LoadProperty";
150 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
151 return "LoadGlobalInsideTypeof";
152 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
153 return "LoadGlobalNotInsideTypeof";
154 case FeedbackSlotKind::kLoadKeyed:
155 return "LoadKeyed";
156 case FeedbackSlotKind::kHasKeyed:
157 return "HasKeyed";
158 case FeedbackSlotKind::kStoreNamedSloppy:
159 return "StoreNamedSloppy";
160 case FeedbackSlotKind::kStoreNamedStrict:
161 return "StoreNamedStrict";
162 case FeedbackSlotKind::kStoreOwnNamed:
163 return "StoreOwnNamed";
164 case FeedbackSlotKind::kStoreGlobalSloppy:
165 return "StoreGlobalSloppy";
166 case FeedbackSlotKind::kStoreGlobalStrict:
167 return "StoreGlobalStrict";
168 case FeedbackSlotKind::kStoreKeyedSloppy:
169 return "StoreKeyedSloppy";
170 case FeedbackSlotKind::kStoreKeyedStrict:
171 return "StoreKeyedStrict";
172 case FeedbackSlotKind::kStoreInArrayLiteral:
173 return "StoreInArrayLiteral";
174 case FeedbackSlotKind::kBinaryOp:
175 return "BinaryOp";
176 case FeedbackSlotKind::kCompareOp:
177 return "CompareOp";
178 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
179 return "StoreDataPropertyInLiteral";
180 case FeedbackSlotKind::kLiteral:
181 return "Literal";
182 case FeedbackSlotKind::kTypeProfile:
183 return "TypeProfile";
184 case FeedbackSlotKind::kForIn:
185 return "ForIn";
186 case FeedbackSlotKind::kInstanceOf:
187 return "InstanceOf";
188 case FeedbackSlotKind::kCloneObject:
189 return "CloneObject";
190 case FeedbackSlotKind::kKindsNumber:
191 break;
192 }
193 UNREACHABLE();
194 }
195
HasTypeProfileSlot() const196 bool FeedbackMetadata::HasTypeProfileSlot() const {
197 FeedbackSlot slot =
198 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
199 return slot.ToInt() < slot_count() &&
200 GetKind(slot) == FeedbackSlotKind::kTypeProfile;
201 }
202
GetKind(FeedbackSlot slot) const203 FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
204 DCHECK(!is_empty());
205 return metadata().GetKind(slot);
206 }
207
GetTypeProfileSlot() const208 FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
209 DCHECK(metadata().HasTypeProfileSlot());
210 FeedbackSlot slot =
211 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
212 DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
213 return slot;
214 }
215
216 // static
New(Isolate * isolate,Handle<SharedFunctionInfo> shared)217 Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
218 Isolate* isolate, Handle<SharedFunctionInfo> shared) {
219 Factory* factory = isolate->factory();
220
221 int num_feedback_cells =
222 shared->feedback_metadata().create_closure_slot_count();
223
224 Handle<ClosureFeedbackCellArray> feedback_cell_array =
225 factory->NewClosureFeedbackCellArray(num_feedback_cells);
226
227 for (int i = 0; i < num_feedback_cells; i++) {
228 Handle<FeedbackCell> cell =
229 factory->NewNoClosuresCell(factory->undefined_value());
230 feedback_cell_array->set(i, *cell);
231 }
232 return feedback_cell_array;
233 }
234
235 // static
New(Isolate * isolate,Handle<SharedFunctionInfo> shared,Handle<ClosureFeedbackCellArray> closure_feedback_cell_array,IsCompiledScope * is_compiled_scope)236 Handle<FeedbackVector> FeedbackVector::New(
237 Isolate* isolate, Handle<SharedFunctionInfo> shared,
238 Handle<ClosureFeedbackCellArray> closure_feedback_cell_array,
239 IsCompiledScope* is_compiled_scope) {
240 DCHECK(is_compiled_scope->is_compiled());
241 Factory* factory = isolate->factory();
242
243 Handle<FeedbackMetadata> feedback_metadata(shared->feedback_metadata(),
244 isolate);
245 const int slot_count = feedback_metadata->slot_count();
246
247 Handle<FeedbackVector> vector =
248 factory->NewFeedbackVector(shared, closure_feedback_cell_array);
249
250 DCHECK_EQ(vector->length(), slot_count);
251
252 DCHECK_EQ(vector->shared_function_info(), *shared);
253 DCHECK_EQ(vector->optimization_marker(),
254 FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
255 : OptimizationMarker::kNone);
256 // TODO(mythria): This might change if NCI code is installed on feedback
257 // vector. Update this accordingly.
258 DCHECK_EQ(vector->optimization_tier(), OptimizationTier::kNone);
259 DCHECK_EQ(vector->invocation_count(), 0);
260 DCHECK_EQ(vector->profiler_ticks(), 0);
261 DCHECK(vector->maybe_optimized_code()->IsCleared());
262
263 // Ensure we can skip the write barrier
264 Handle<Symbol> uninitialized_sentinel = UninitializedSentinel(isolate);
265 DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
266 *uninitialized_sentinel);
267 for (int i = 0; i < slot_count;) {
268 FeedbackSlot slot(i);
269 FeedbackSlotKind kind = feedback_metadata->GetKind(slot);
270 int entry_size = FeedbackMetadata::GetSlotSize(kind);
271
272 MaybeObject extra_value = MaybeObject::FromObject(*uninitialized_sentinel);
273 switch (kind) {
274 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
275 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
276 case FeedbackSlotKind::kStoreGlobalSloppy:
277 case FeedbackSlotKind::kStoreGlobalStrict:
278 vector->Set(slot, HeapObjectReference::ClearedValue(isolate),
279 SKIP_WRITE_BARRIER);
280 break;
281 case FeedbackSlotKind::kForIn:
282 case FeedbackSlotKind::kCompareOp:
283 case FeedbackSlotKind::kBinaryOp:
284 vector->Set(slot, Smi::zero(), SKIP_WRITE_BARRIER);
285 break;
286 case FeedbackSlotKind::kLiteral:
287 vector->Set(slot, Smi::zero(), SKIP_WRITE_BARRIER);
288 break;
289 case FeedbackSlotKind::kCall:
290 vector->Set(slot, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
291 extra_value = MaybeObject::FromObject(Smi::zero());
292 break;
293 case FeedbackSlotKind::kCloneObject:
294 case FeedbackSlotKind::kLoadProperty:
295 case FeedbackSlotKind::kLoadKeyed:
296 case FeedbackSlotKind::kHasKeyed:
297 case FeedbackSlotKind::kStoreNamedSloppy:
298 case FeedbackSlotKind::kStoreNamedStrict:
299 case FeedbackSlotKind::kStoreOwnNamed:
300 case FeedbackSlotKind::kStoreKeyedSloppy:
301 case FeedbackSlotKind::kStoreKeyedStrict:
302 case FeedbackSlotKind::kStoreInArrayLiteral:
303 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
304 case FeedbackSlotKind::kTypeProfile:
305 case FeedbackSlotKind::kInstanceOf:
306 vector->Set(slot, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
307 break;
308
309 case FeedbackSlotKind::kInvalid:
310 case FeedbackSlotKind::kKindsNumber:
311 UNREACHABLE();
312 break;
313 }
314 for (int j = 1; j < entry_size; j++) {
315 vector->Set(slot.WithOffset(j), extra_value, SKIP_WRITE_BARRIER);
316 }
317 i += entry_size;
318 }
319
320 Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
321 if (!isolate->is_best_effort_code_coverage() ||
322 isolate->is_collecting_type_profile()) {
323 AddToVectorsForProfilingTools(isolate, result);
324 }
325 return result;
326 }
327
328 namespace {
329
NewFeedbackVectorForTesting(Isolate * isolate,const FeedbackVectorSpec * spec)330 Handle<FeedbackVector> NewFeedbackVectorForTesting(
331 Isolate* isolate, const FeedbackVectorSpec* spec) {
332 Handle<FeedbackMetadata> metadata = FeedbackMetadata::New(isolate, spec);
333 Handle<SharedFunctionInfo> shared =
334 isolate->factory()->NewSharedFunctionInfoForBuiltin(
335 isolate->factory()->empty_string(), Builtins::kIllegal);
336 // Set the raw feedback metadata to circumvent checks that we are not
337 // overwriting existing metadata.
338 shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
339 Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
340 ClosureFeedbackCellArray::New(isolate, shared);
341
342 IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
343 return FeedbackVector::New(isolate, shared, closure_feedback_cell_array,
344 &is_compiled_scope);
345 }
346
347 } // namespace
348
349 // static
NewWithOneBinarySlotForTesting(Zone * zone,Isolate * isolate)350 Handle<FeedbackVector> FeedbackVector::NewWithOneBinarySlotForTesting(
351 Zone* zone, Isolate* isolate) {
352 FeedbackVectorSpec one_slot(zone);
353 one_slot.AddBinaryOpICSlot();
354 return NewFeedbackVectorForTesting(isolate, &one_slot);
355 }
356
357 // static
NewWithOneCompareSlotForTesting(Zone * zone,Isolate * isolate)358 Handle<FeedbackVector> FeedbackVector::NewWithOneCompareSlotForTesting(
359 Zone* zone, Isolate* isolate) {
360 FeedbackVectorSpec one_slot(zone);
361 one_slot.AddCompareICSlot();
362 return NewFeedbackVectorForTesting(isolate, &one_slot);
363 }
364
365 // static
AddToVectorsForProfilingTools(Isolate * isolate,Handle<FeedbackVector> vector)366 void FeedbackVector::AddToVectorsForProfilingTools(
367 Isolate* isolate, Handle<FeedbackVector> vector) {
368 DCHECK(!isolate->is_best_effort_code_coverage() ||
369 isolate->is_collecting_type_profile());
370 if (!vector->shared_function_info().IsSubjectToDebugging()) return;
371 Handle<ArrayList> list = Handle<ArrayList>::cast(
372 isolate->factory()->feedback_vectors_for_profiling_tools());
373 list = ArrayList::Add(isolate, list, vector);
374 isolate->SetFeedbackVectorsForProfilingTools(*list);
375 }
376
SaturatingIncrementProfilerTicks()377 void FeedbackVector::SaturatingIncrementProfilerTicks() {
378 int ticks = profiler_ticks();
379 if (ticks < Smi::kMaxValue) set_profiler_ticks(ticks + 1);
380 }
381
382 // static
SetOptimizedCode(Handle<FeedbackVector> vector,Handle<Code> code)383 void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
384 Handle<Code> code) {
385 DCHECK(CodeKindIsOptimizedJSFunction(code->kind()));
386 // We should only set optimized code only when there is no valid optimized
387 // code or we are tiering up.
388 DCHECK(!vector->has_optimized_code() ||
389 vector->optimized_code().marked_for_deoptimization() ||
390 (vector->optimized_code().kind() == CodeKind::TURBOPROP &&
391 code->kind() == CodeKind::TURBOFAN));
392 // TODO(mythria): We could see a CompileOptimized marker here either from
393 // tests that use %OptimizeFunctionOnNextCall or because we re-mark the
394 // function for non-concurrent optimization after an OSR. We should avoid
395 // these cases and also check that marker isn't kCompileOptimized.
396 DCHECK(vector->optimization_marker() !=
397 OptimizationMarker::kCompileOptimizedConcurrent);
398 vector->set_maybe_optimized_code(HeapObjectReference::Weak(*code));
399 int32_t state = vector->flags();
400 state = OptimizationTierBits::update(state, GetTierForCodeKind(code->kind()));
401 state = OptimizationMarkerBits::update(state, OptimizationMarker::kNone);
402 vector->set_flags(state);
403 }
404
ClearOptimizedCode()405 void FeedbackVector::ClearOptimizedCode() {
406 DCHECK(has_optimized_code());
407 DCHECK_NE(optimization_tier(), OptimizationTier::kNone);
408 set_maybe_optimized_code(HeapObjectReference::ClearedValue(GetIsolate()));
409 ClearOptimizationTier();
410 }
411
ClearOptimizationMarker()412 void FeedbackVector::ClearOptimizationMarker() {
413 SetOptimizationMarker(OptimizationMarker::kNone);
414 }
415
SetOptimizationMarker(OptimizationMarker marker)416 void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
417 int32_t state = flags();
418 state = OptimizationMarkerBits::update(state, marker);
419 set_flags(state);
420 }
421
ClearOptimizationTier()422 void FeedbackVector::ClearOptimizationTier() {
423 int32_t state = flags();
424 state = OptimizationTierBits::update(state, OptimizationTier::kNone);
425 set_flags(state);
426 }
427
InitializeOptimizationState()428 void FeedbackVector::InitializeOptimizationState() {
429 int32_t state = 0;
430 state = OptimizationMarkerBits::update(
431 state, FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
432 : OptimizationMarker::kNone);
433 state = OptimizationTierBits::update(state, OptimizationTier::kNone);
434 set_flags(state);
435 }
436
EvictOptimizedCodeMarkedForDeoptimization(SharedFunctionInfo shared,const char * reason)437 void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
438 SharedFunctionInfo shared, const char* reason) {
439 MaybeObject slot = maybe_optimized_code();
440 if (slot->IsCleared()) {
441 ClearOptimizationTier();
442 return;
443 }
444
445 Code code = Code::cast(slot->GetHeapObject());
446 if (code.marked_for_deoptimization()) {
447 Deoptimizer::TraceEvictFromOptimizedCodeCache(shared, reason);
448 if (!code.deopt_already_counted()) {
449 code.set_deopt_already_counted(true);
450 }
451 ClearOptimizedCode();
452 }
453 }
454
ClearSlots(Isolate * isolate)455 bool FeedbackVector::ClearSlots(Isolate* isolate) {
456 if (!shared_function_info().HasFeedbackMetadata()) return false;
457 MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
458 FeedbackVector::RawUninitializedSentinel(isolate));
459
460 bool feedback_updated = false;
461 FeedbackMetadataIterator iter(metadata());
462 while (iter.HasNext()) {
463 FeedbackSlot slot = iter.Next();
464
465 MaybeObject obj = Get(slot);
466 if (obj != uninitialized_sentinel) {
467 FeedbackNexus nexus(*this, slot);
468 feedback_updated |= nexus.Clear();
469 }
470 }
471 return feedback_updated;
472 }
473
NewHandle(MaybeObject object) const474 MaybeObjectHandle NexusConfig::NewHandle(MaybeObject object) const {
475 if (mode() == Mode::MainThread) {
476 return handle(object, isolate_);
477 }
478 DCHECK_EQ(mode(), Mode::BackgroundThread);
479 return handle(object, local_heap_);
480 }
481
482 template <typename T>
NewHandle(T object) const483 Handle<T> NexusConfig::NewHandle(T object) const {
484 if (mode() == Mode::MainThread) {
485 return handle(object, isolate_);
486 }
487 DCHECK_EQ(mode(), Mode::BackgroundThread);
488 return handle(object, local_heap_);
489 }
490
SetFeedbackPair(FeedbackVector vector,FeedbackSlot start_slot,MaybeObject feedback,WriteBarrierMode mode,MaybeObject feedback_extra,WriteBarrierMode mode_extra) const491 void NexusConfig::SetFeedbackPair(FeedbackVector vector,
492 FeedbackSlot start_slot, MaybeObject feedback,
493 WriteBarrierMode mode,
494 MaybeObject feedback_extra,
495 WriteBarrierMode mode_extra) const {
496 CHECK(can_write());
497 CHECK_GT(vector.length(), start_slot.WithOffset(1).ToInt());
498 base::SharedMutexGuard<base::kExclusive> shared_mutex_guard(
499 isolate()->feedback_vector_access());
500 vector.Set(start_slot, feedback, mode);
501 vector.Set(start_slot.WithOffset(1), feedback_extra, mode_extra);
502 }
503
GetFeedbackPair(FeedbackVector vector,FeedbackSlot slot) const504 std::pair<MaybeObject, MaybeObject> NexusConfig::GetFeedbackPair(
505 FeedbackVector vector, FeedbackSlot slot) const {
506 if (mode() == BackgroundThread) {
507 isolate()->feedback_vector_access()->LockShared();
508 }
509 MaybeObject feedback = vector.Get(slot);
510 MaybeObject feedback_extra = vector.Get(slot.WithOffset(1));
511 auto return_value = std::make_pair(feedback, feedback_extra);
512 if (mode() == BackgroundThread) {
513 isolate()->feedback_vector_access()->UnlockShared();
514 }
515 return return_value;
516 }
517
FeedbackNexus(Handle<FeedbackVector> vector,FeedbackSlot slot)518 FeedbackNexus::FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
519 : vector_handle_(vector),
520 slot_(slot),
521 config_(NexusConfig::FromMainThread(
522 vector.is_null() ? nullptr : vector->GetIsolate())) {
523 kind_ = vector.is_null() ? FeedbackSlotKind::kInvalid : vector->GetKind(slot);
524 }
525
FeedbackNexus(FeedbackVector vector,FeedbackSlot slot)526 FeedbackNexus::FeedbackNexus(FeedbackVector vector, FeedbackSlot slot)
527 : vector_(vector),
528 slot_(slot),
529 config_(NexusConfig::FromMainThread(
530 vector.is_null() ? nullptr : vector.GetIsolate())) {
531 kind_ = vector.is_null() ? FeedbackSlotKind::kInvalid : vector.GetKind(slot);
532 }
533
FeedbackNexus(Handle<FeedbackVector> vector,FeedbackSlot slot,const NexusConfig & config)534 FeedbackNexus::FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot,
535 const NexusConfig& config)
536 : vector_handle_(vector),
537 slot_(slot),
538 kind_(vector->GetKind(slot)),
539 config_(config) {}
540
CreateArrayOfSize(int length)541 Handle<WeakFixedArray> FeedbackNexus::CreateArrayOfSize(int length) {
542 DCHECK(config()->can_write());
543 Handle<WeakFixedArray> array =
544 GetIsolate()->factory()->NewWeakFixedArray(length);
545 return array;
546 }
547
ConfigureUninitialized()548 void FeedbackNexus::ConfigureUninitialized() {
549 Isolate* isolate = GetIsolate();
550 switch (kind()) {
551 case FeedbackSlotKind::kStoreGlobalSloppy:
552 case FeedbackSlotKind::kStoreGlobalStrict:
553 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
554 case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
555 SetFeedback(HeapObjectReference::ClearedValue(isolate),
556 SKIP_WRITE_BARRIER, UninitializedSentinel(),
557 SKIP_WRITE_BARRIER);
558 break;
559 }
560 case FeedbackSlotKind::kCloneObject:
561 case FeedbackSlotKind::kCall: {
562 SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER, Smi::zero(),
563 SKIP_WRITE_BARRIER);
564 break;
565 }
566 case FeedbackSlotKind::kInstanceOf: {
567 SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER);
568 break;
569 }
570 case FeedbackSlotKind::kStoreNamedSloppy:
571 case FeedbackSlotKind::kStoreNamedStrict:
572 case FeedbackSlotKind::kStoreKeyedSloppy:
573 case FeedbackSlotKind::kStoreKeyedStrict:
574 case FeedbackSlotKind::kStoreInArrayLiteral:
575 case FeedbackSlotKind::kStoreOwnNamed:
576 case FeedbackSlotKind::kLoadProperty:
577 case FeedbackSlotKind::kLoadKeyed:
578 case FeedbackSlotKind::kHasKeyed:
579 case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
580 SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER,
581 UninitializedSentinel(), SKIP_WRITE_BARRIER);
582 break;
583 }
584 default:
585 UNREACHABLE();
586 }
587 }
588
Clear()589 bool FeedbackNexus::Clear() {
590 bool feedback_updated = false;
591
592 switch (kind()) {
593 case FeedbackSlotKind::kTypeProfile:
594 // We don't clear these kinds ever.
595 break;
596
597 case FeedbackSlotKind::kCompareOp:
598 case FeedbackSlotKind::kForIn:
599 case FeedbackSlotKind::kBinaryOp:
600 // We don't clear these, either.
601 break;
602
603 case FeedbackSlotKind::kLiteral:
604 SetFeedback(Smi::zero(), SKIP_WRITE_BARRIER);
605 feedback_updated = true;
606 break;
607
608 case FeedbackSlotKind::kStoreNamedSloppy:
609 case FeedbackSlotKind::kStoreNamedStrict:
610 case FeedbackSlotKind::kStoreKeyedSloppy:
611 case FeedbackSlotKind::kStoreKeyedStrict:
612 case FeedbackSlotKind::kStoreInArrayLiteral:
613 case FeedbackSlotKind::kStoreOwnNamed:
614 case FeedbackSlotKind::kLoadProperty:
615 case FeedbackSlotKind::kLoadKeyed:
616 case FeedbackSlotKind::kHasKeyed:
617 case FeedbackSlotKind::kStoreGlobalSloppy:
618 case FeedbackSlotKind::kStoreGlobalStrict:
619 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
620 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
621 case FeedbackSlotKind::kCall:
622 case FeedbackSlotKind::kInstanceOf:
623 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
624 case FeedbackSlotKind::kCloneObject:
625 if (!IsCleared()) {
626 ConfigureUninitialized();
627 feedback_updated = true;
628 }
629 break;
630
631 case FeedbackSlotKind::kInvalid:
632 case FeedbackSlotKind::kKindsNumber:
633 UNREACHABLE();
634 }
635 return feedback_updated;
636 }
637
ConfigureMegamorphic()638 bool FeedbackNexus::ConfigureMegamorphic() {
639 DisallowHeapAllocation no_gc;
640 Isolate* isolate = GetIsolate();
641 MaybeObject sentinel = MegamorphicSentinel();
642 if (GetFeedback() != sentinel) {
643 SetFeedback(sentinel, SKIP_WRITE_BARRIER,
644 HeapObjectReference::ClearedValue(isolate));
645 return true;
646 }
647
648 return false;
649 }
650
ConfigureMegamorphic(IcCheckType property_type)651 bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
652 DisallowHeapAllocation no_gc;
653 MaybeObject sentinel = MegamorphicSentinel();
654 MaybeObject maybe_extra =
655 MaybeObject::FromSmi(Smi::FromInt(static_cast<int>(property_type)));
656
657 auto feedback = GetFeedbackPair();
658 bool update_required =
659 feedback.first != sentinel || feedback.second != maybe_extra;
660 if (update_required) {
661 SetFeedback(sentinel, SKIP_WRITE_BARRIER, maybe_extra, SKIP_WRITE_BARRIER);
662 }
663 return update_required;
664 }
665
GetFirstMap() const666 Map FeedbackNexus::GetFirstMap() const {
667 FeedbackIterator it(this);
668 if (!it.done()) {
669 return it.map();
670 }
671
672 return Map();
673 }
674
ic_state() const675 InlineCacheState FeedbackNexus::ic_state() const {
676 MaybeObject feedback, extra;
677 std::tie(feedback, extra) = GetFeedbackPair();
678
679 switch (kind()) {
680 case FeedbackSlotKind::kLiteral:
681 if (feedback->IsSmi()) return UNINITIALIZED;
682 return MONOMORPHIC;
683
684 case FeedbackSlotKind::kStoreGlobalSloppy:
685 case FeedbackSlotKind::kStoreGlobalStrict:
686 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
687 case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
688 if (feedback->IsSmi()) return MONOMORPHIC;
689
690 DCHECK(feedback->IsWeakOrCleared());
691 if (!feedback->IsCleared() || extra != UninitializedSentinel()) {
692 return MONOMORPHIC;
693 }
694 return UNINITIALIZED;
695 }
696
697 case FeedbackSlotKind::kStoreNamedSloppy:
698 case FeedbackSlotKind::kStoreNamedStrict:
699 case FeedbackSlotKind::kStoreKeyedSloppy:
700 case FeedbackSlotKind::kStoreKeyedStrict:
701 case FeedbackSlotKind::kStoreInArrayLiteral:
702 case FeedbackSlotKind::kStoreOwnNamed:
703 case FeedbackSlotKind::kLoadProperty:
704 case FeedbackSlotKind::kLoadKeyed:
705 case FeedbackSlotKind::kHasKeyed: {
706 if (feedback == UninitializedSentinel()) {
707 return UNINITIALIZED;
708 }
709 if (feedback == MegamorphicSentinel()) {
710 return MEGAMORPHIC;
711 }
712 if (feedback->IsWeakOrCleared()) {
713 // Don't check if the map is cleared.
714 return MONOMORPHIC;
715 }
716 HeapObject heap_object;
717 if (feedback->GetHeapObjectIfStrong(&heap_object)) {
718 if (heap_object.IsWeakFixedArray()) {
719 // Determine state purely by our structure, don't check if the maps
720 // are cleared.
721 return POLYMORPHIC;
722 }
723 if (heap_object.IsName()) {
724 DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
725 IsKeyedHasICKind(kind()));
726 Object extra_object = extra->GetHeapObjectAssumeStrong();
727 WeakFixedArray extra_array = WeakFixedArray::cast(extra_object);
728 return extra_array.length() > 2 ? POLYMORPHIC : MONOMORPHIC;
729 }
730 }
731 UNREACHABLE();
732 }
733 case FeedbackSlotKind::kCall: {
734 HeapObject heap_object;
735 if (feedback == MegamorphicSentinel()) {
736 return GENERIC;
737 } else if (feedback->IsWeakOrCleared()) {
738 if (feedback->GetHeapObjectIfWeak(&heap_object)) {
739 if (heap_object.IsFeedbackCell()) {
740 return POLYMORPHIC;
741 }
742 CHECK(heap_object.IsJSFunction() || heap_object.IsJSBoundFunction());
743 }
744 return MONOMORPHIC;
745 } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
746 heap_object.IsAllocationSite()) {
747 return MONOMORPHIC;
748 }
749
750 CHECK_EQ(feedback, UninitializedSentinel());
751 return UNINITIALIZED;
752 }
753 case FeedbackSlotKind::kBinaryOp: {
754 BinaryOperationHint hint = GetBinaryOperationFeedback();
755 if (hint == BinaryOperationHint::kNone) {
756 return UNINITIALIZED;
757 } else if (hint == BinaryOperationHint::kAny) {
758 return GENERIC;
759 }
760
761 return MONOMORPHIC;
762 }
763 case FeedbackSlotKind::kCompareOp: {
764 CompareOperationHint hint = GetCompareOperationFeedback();
765 if (hint == CompareOperationHint::kNone) {
766 return UNINITIALIZED;
767 } else if (hint == CompareOperationHint::kAny) {
768 return GENERIC;
769 }
770
771 return MONOMORPHIC;
772 }
773 case FeedbackSlotKind::kForIn: {
774 ForInHint hint = GetForInFeedback();
775 if (hint == ForInHint::kNone) {
776 return UNINITIALIZED;
777 } else if (hint == ForInHint::kAny) {
778 return GENERIC;
779 }
780 return MONOMORPHIC;
781 }
782 case FeedbackSlotKind::kInstanceOf: {
783 if (feedback == UninitializedSentinel()) {
784 return UNINITIALIZED;
785 } else if (feedback == MegamorphicSentinel()) {
786 return MEGAMORPHIC;
787 }
788 return MONOMORPHIC;
789 }
790 case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
791 if (feedback == UninitializedSentinel()) {
792 return UNINITIALIZED;
793 } else if (feedback->IsWeakOrCleared()) {
794 // Don't check if the map is cleared.
795 return MONOMORPHIC;
796 }
797
798 return MEGAMORPHIC;
799 }
800 case FeedbackSlotKind::kTypeProfile: {
801 if (feedback == UninitializedSentinel()) {
802 return UNINITIALIZED;
803 }
804 return MONOMORPHIC;
805 }
806
807 case FeedbackSlotKind::kCloneObject: {
808 if (feedback == UninitializedSentinel()) {
809 return UNINITIALIZED;
810 }
811 if (feedback == MegamorphicSentinel()) {
812 return MEGAMORPHIC;
813 }
814 if (feedback->IsWeakOrCleared()) {
815 return MONOMORPHIC;
816 }
817
818 DCHECK(feedback->GetHeapObjectAssumeStrong().IsWeakFixedArray());
819 return POLYMORPHIC;
820 }
821
822 case FeedbackSlotKind::kInvalid:
823 case FeedbackSlotKind::kKindsNumber:
824 UNREACHABLE();
825 }
826 return UNINITIALIZED;
827 }
828
ConfigurePropertyCellMode(Handle<PropertyCell> cell)829 void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
830 DCHECK(IsGlobalICKind(kind()));
831 SetFeedback(HeapObjectReference::Weak(*cell), UPDATE_WRITE_BARRIER,
832 UninitializedSentinel(), SKIP_WRITE_BARRIER);
833 }
834
ConfigureLexicalVarMode(int script_context_index,int context_slot_index,bool immutable)835 bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
836 int context_slot_index,
837 bool immutable) {
838 DCHECK(IsGlobalICKind(kind()));
839 DCHECK_LE(0, script_context_index);
840 DCHECK_LE(0, context_slot_index);
841 if (!ContextIndexBits::is_valid(script_context_index) ||
842 !SlotIndexBits::is_valid(context_slot_index) ||
843 !ImmutabilityBit::is_valid(immutable)) {
844 return false;
845 }
846 int config = ContextIndexBits::encode(script_context_index) |
847 SlotIndexBits::encode(context_slot_index) |
848 ImmutabilityBit::encode(immutable);
849
850 SetFeedback(Smi::From31BitPattern(config), SKIP_WRITE_BARRIER,
851 UninitializedSentinel(), SKIP_WRITE_BARRIER);
852 return true;
853 }
854
ConfigureHandlerMode(const MaybeObjectHandle & handler)855 void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
856 DCHECK(IsGlobalICKind(kind()));
857 DCHECK(IC::IsHandler(*handler));
858 SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()),
859 UPDATE_WRITE_BARRIER, *handler, UPDATE_WRITE_BARRIER);
860 }
861
ConfigureCloneObject(Handle<Map> source_map,Handle<Map> result_map)862 void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
863 Handle<Map> result_map) {
864 DCHECK(config()->can_write());
865 Isolate* isolate = GetIsolate();
866 Handle<HeapObject> feedback;
867 {
868 MaybeObject maybe_feedback = GetFeedback();
869 if (maybe_feedback->IsStrongOrWeak()) {
870 feedback = handle(maybe_feedback->GetHeapObject(), isolate);
871 } else {
872 DCHECK(maybe_feedback->IsCleared());
873 }
874 }
875 switch (ic_state()) {
876 case UNINITIALIZED:
877 // Cache the first map seen which meets the fast case requirements.
878 SetFeedback(HeapObjectReference::Weak(*source_map), UPDATE_WRITE_BARRIER,
879 *result_map);
880 break;
881 case MONOMORPHIC:
882 if (feedback.is_null() || feedback.is_identical_to(source_map) ||
883 Map::cast(*feedback).is_deprecated()) {
884 SetFeedback(HeapObjectReference::Weak(*source_map),
885 UPDATE_WRITE_BARRIER, *result_map);
886 } else {
887 // Transition to POLYMORPHIC.
888 Handle<WeakFixedArray> array =
889 CreateArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
890 array->Set(0, HeapObjectReference::Weak(*feedback));
891 array->Set(1, GetFeedbackExtra());
892 array->Set(2, HeapObjectReference::Weak(*source_map));
893 array->Set(3, MaybeObject::FromObject(*result_map));
894 SetFeedback(*array, UPDATE_WRITE_BARRIER,
895 HeapObjectReference::ClearedValue(isolate));
896 }
897 break;
898 case POLYMORPHIC: {
899 const int kMaxElements = FLAG_max_valid_polymorphic_map_count *
900 kCloneObjectPolymorphicEntrySize;
901 Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
902 int i = 0;
903 for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
904 MaybeObject feedback_map = array->Get(i);
905 if (feedback_map->IsCleared()) break;
906 Handle<Map> cached_map(Map::cast(feedback_map->GetHeapObject()),
907 isolate);
908 if (cached_map.is_identical_to(source_map) ||
909 cached_map->is_deprecated())
910 break;
911 }
912
913 if (i >= array->length()) {
914 if (i == kMaxElements) {
915 // Transition to MEGAMORPHIC.
916 MaybeObject sentinel = MegamorphicSentinel();
917 SetFeedback(sentinel, SKIP_WRITE_BARRIER,
918 HeapObjectReference::ClearedValue(isolate));
919 break;
920 }
921
922 // Grow polymorphic feedback array.
923 Handle<WeakFixedArray> new_array = CreateArrayOfSize(
924 array->length() + kCloneObjectPolymorphicEntrySize);
925 for (int j = 0; j < array->length(); ++j) {
926 new_array->Set(j, array->Get(j));
927 }
928 SetFeedback(*new_array);
929 array = new_array;
930 }
931
932 array->Set(i, HeapObjectReference::Weak(*source_map));
933 array->Set(i + 1, MaybeObject::FromObject(*result_map));
934 break;
935 }
936
937 default:
938 UNREACHABLE();
939 }
940 }
941
GetCallCount()942 int FeedbackNexus::GetCallCount() {
943 DCHECK(IsCallICKind(kind()));
944
945 Object call_count = GetFeedbackExtra()->cast<Object>();
946 CHECK(call_count.IsSmi());
947 uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
948 return CallCountField::decode(value);
949 }
950
SetSpeculationMode(SpeculationMode mode)951 void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
952 DCHECK(IsCallICKind(kind()));
953
954 Object call_count = GetFeedbackExtra()->cast<Object>();
955 CHECK(call_count.IsSmi());
956 uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
957 uint32_t value = CallCountField::encode(CallCountField::decode(count));
958 int result = static_cast<int>(value | SpeculationModeField::encode(mode));
959 MaybeObject feedback = GetFeedback();
960 // We can skip the write barrier for {feedback} because it's not changing.
961 SetFeedback(feedback, SKIP_WRITE_BARRIER, Smi::FromInt(result),
962 SKIP_WRITE_BARRIER);
963 }
964
GetSpeculationMode()965 SpeculationMode FeedbackNexus::GetSpeculationMode() {
966 DCHECK(IsCallICKind(kind()));
967
968 Object call_count = GetFeedbackExtra()->cast<Object>();
969 CHECK(call_count.IsSmi());
970 uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
971 return SpeculationModeField::decode(value);
972 }
973
ComputeCallFrequency()974 float FeedbackNexus::ComputeCallFrequency() {
975 DCHECK(IsCallICKind(kind()));
976
977 double const invocation_count = vector().invocation_count();
978 double const call_count = GetCallCount();
979 if (invocation_count == 0.0) { // Prevent division by 0.
980 return 0.0f;
981 }
982 return static_cast<float>(call_count / invocation_count);
983 }
984
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,const MaybeObjectHandle & handler)985 void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
986 Handle<Map> receiver_map,
987 const MaybeObjectHandle& handler) {
988 DCHECK(handler.is_null() || IC::IsHandler(*handler));
989 if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
990 SetFeedback(HeapObjectReference::Weak(*receiver_map), UPDATE_WRITE_BARRIER,
991 *name);
992 } else {
993 if (name.is_null()) {
994 SetFeedback(HeapObjectReference::Weak(*receiver_map),
995 UPDATE_WRITE_BARRIER, *handler);
996 } else {
997 Handle<WeakFixedArray> array = CreateArrayOfSize(2);
998 array->Set(0, HeapObjectReference::Weak(*receiver_map));
999 array->Set(1, *handler);
1000 SetFeedback(*name, UPDATE_WRITE_BARRIER, *array);
1001 }
1002 }
1003 }
1004
ConfigurePolymorphic(Handle<Name> name,std::vector<MapAndHandler> const & maps_and_handlers)1005 void FeedbackNexus::ConfigurePolymorphic(
1006 Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers) {
1007 int receiver_count = static_cast<int>(maps_and_handlers.size());
1008 DCHECK_GT(receiver_count, 1);
1009 Handle<WeakFixedArray> array = CreateArrayOfSize(receiver_count * 2);
1010
1011 for (int current = 0; current < receiver_count; ++current) {
1012 Handle<Map> map = maps_and_handlers[current].first;
1013 array->Set(current * 2, HeapObjectReference::Weak(*map));
1014 MaybeObjectHandle handler = maps_and_handlers[current].second;
1015 DCHECK(IC::IsHandler(*handler));
1016 array->Set(current * 2 + 1, *handler);
1017 }
1018
1019 if (name.is_null()) {
1020 SetFeedback(*array, UPDATE_WRITE_BARRIER, UninitializedSentinel(),
1021 SKIP_WRITE_BARRIER);
1022 } else {
1023 SetFeedback(*name, UPDATE_WRITE_BARRIER, *array);
1024 }
1025 }
1026
ExtractMaps(MapHandles * maps) const1027 int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
1028 DisallowHeapAllocation no_gc;
1029 int found = 0;
1030 for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1031 maps->push_back(config()->NewHandle(it.map()));
1032 found++;
1033 }
1034
1035 return found;
1036 }
1037
ExtractMapsAndFeedback(std::vector<MapAndFeedback> * maps_and_feedback) const1038 int FeedbackNexus::ExtractMapsAndFeedback(
1039 std::vector<MapAndFeedback>* maps_and_feedback) const {
1040 DisallowHeapAllocation no_gc;
1041 int found = 0;
1042
1043 for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1044 Handle<Map> map = config()->NewHandle(it.map());
1045 MaybeObject maybe_handler = it.handler();
1046 if (!maybe_handler->IsCleared()) {
1047 DCHECK(IC::IsHandler(maybe_handler) ||
1048 IsStoreDataPropertyInLiteralKind(kind()));
1049 MaybeObjectHandle handler = config()->NewHandle(maybe_handler);
1050 maps_and_feedback->push_back(MapAndHandler(map, handler));
1051 found++;
1052 }
1053 }
1054
1055 return found;
1056 }
1057
ExtractMapsAndHandlers(std::vector<MapAndHandler> * maps_and_handlers,TryUpdateHandler map_handler) const1058 int FeedbackNexus::ExtractMapsAndHandlers(
1059 std::vector<MapAndHandler>* maps_and_handlers,
1060 TryUpdateHandler map_handler) const {
1061 DCHECK(!IsStoreDataPropertyInLiteralKind(kind()));
1062 DisallowHeapAllocation no_gc;
1063 int found = 0;
1064
1065 for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1066 Handle<Map> map = config()->NewHandle(it.map());
1067 MaybeObject maybe_handler = it.handler();
1068 if (!maybe_handler->IsCleared()) {
1069 DCHECK(IC::IsHandler(maybe_handler));
1070 MaybeObjectHandle handler = config()->NewHandle(maybe_handler);
1071 if (map_handler && !(map_handler(map).ToHandle(&map))) {
1072 continue;
1073 }
1074 maps_and_handlers->push_back(MapAndHandler(map, handler));
1075 found++;
1076 }
1077 }
1078
1079 return found;
1080 }
1081
FindHandlerForMap(Handle<Map> map) const1082 MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
1083 DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1084
1085 for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1086 if (it.map() == *map && !it.handler()->IsCleared()) {
1087 return config()->NewHandle(it.handler());
1088 }
1089 }
1090 return MaybeObjectHandle();
1091 }
1092
GetName() const1093 Name FeedbackNexus::GetName() const {
1094 if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1095 IsKeyedHasICKind(kind())) {
1096 MaybeObject feedback = GetFeedback();
1097 if (IsPropertyNameFeedback(feedback)) {
1098 return Name::cast(feedback->GetHeapObjectAssumeStrong());
1099 }
1100 }
1101 if (IsStoreDataPropertyInLiteralKind(kind())) {
1102 MaybeObject extra = GetFeedbackExtra();
1103 if (IsPropertyNameFeedback(extra)) {
1104 return Name::cast(extra->GetHeapObjectAssumeStrong());
1105 }
1106 }
1107 return Name();
1108 }
1109
GetKeyedAccessLoadMode() const1110 KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1111 DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
1112
1113 if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1114
1115 std::vector<MapAndHandler> maps_and_handlers;
1116 ExtractMapsAndHandlers(&maps_and_handlers);
1117 for (MapAndHandler map_and_handler : maps_and_handlers) {
1118 KeyedAccessLoadMode mode =
1119 LoadHandler::GetKeyedAccessLoadMode(*map_and_handler.second);
1120 if (mode != STANDARD_LOAD) return mode;
1121 }
1122
1123 return STANDARD_LOAD;
1124 }
1125
1126 namespace {
1127
BuiltinHasKeyedAccessStoreMode(int builtin_index)1128 bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
1129 DCHECK(Builtins::IsBuiltinId(builtin_index));
1130 switch (builtin_index) {
1131 case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1132 case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1133 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1134 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1135 case Builtins::kStoreFastElementIC_Standard:
1136 case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1137 case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1138 case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1139 case Builtins::kElementsTransitionAndStore_Standard:
1140 case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1141 case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1142 case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1143 return true;
1144 default:
1145 return false;
1146 }
1147 UNREACHABLE();
1148 }
1149
KeyedAccessStoreModeForBuiltin(int builtin_index)1150 KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
1151 DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
1152 switch (builtin_index) {
1153 case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1154 case Builtins::kStoreFastElementIC_Standard:
1155 case Builtins::kElementsTransitionAndStore_Standard:
1156 return STANDARD_STORE;
1157 case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1158 case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1159 case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1160 return STORE_AND_GROW_HANDLE_COW;
1161 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1162 case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1163 case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1164 return STORE_IGNORE_OUT_OF_BOUNDS;
1165 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1166 case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1167 case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1168 return STORE_HANDLE_COW;
1169 default:
1170 UNREACHABLE();
1171 }
1172 }
1173
1174 } // namespace
1175
GetKeyedAccessStoreMode() const1176 KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1177 DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()) ||
1178 IsStoreDataPropertyInLiteralKind(kind()));
1179 KeyedAccessStoreMode mode = STANDARD_STORE;
1180
1181 if (GetKeyType() == PROPERTY) return mode;
1182
1183 std::vector<MapAndHandler> maps_and_handlers;
1184 ExtractMapsAndHandlers(&maps_and_handlers);
1185 for (const MapAndHandler& map_and_handler : maps_and_handlers) {
1186 const MaybeObjectHandle maybe_code_handler = map_and_handler.second;
1187 // The first handler that isn't the slow handler will have the bits we need.
1188 Handle<Code> handler;
1189 if (maybe_code_handler.object()->IsStoreHandler()) {
1190 Handle<StoreHandler> data_handler =
1191 Handle<StoreHandler>::cast(maybe_code_handler.object());
1192
1193 if ((data_handler->smi_handler()).IsSmi()) {
1194 // Decode the KeyedAccessStoreMode information from the Handler.
1195 mode = StoreHandler::GetKeyedAccessStoreMode(
1196 MaybeObject::FromObject(data_handler->smi_handler()));
1197 if (mode != STANDARD_STORE) return mode;
1198 continue;
1199 } else {
1200 handler = handle(Code::cast(data_handler->smi_handler()),
1201 vector().GetIsolate());
1202 }
1203
1204 } else if (maybe_code_handler.object()->IsSmi()) {
1205 // Skip for Proxy Handlers.
1206 if (*(maybe_code_handler.object()) ==
1207 *StoreHandler::StoreProxy(GetIsolate()))
1208 continue;
1209 // Decode the KeyedAccessStoreMode information from the Handler.
1210 mode = StoreHandler::GetKeyedAccessStoreMode(*maybe_code_handler);
1211 if (mode != STANDARD_STORE) return mode;
1212 continue;
1213 } else {
1214 // Element store without prototype chain check.
1215 handler = Handle<Code>::cast(maybe_code_handler.object());
1216 }
1217
1218 if (handler->is_builtin()) {
1219 const int builtin_index = handler->builtin_index();
1220 if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;
1221
1222 mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1223 break;
1224 }
1225 }
1226
1227 return mode;
1228 }
1229
GetKeyType() const1230 IcCheckType FeedbackNexus::GetKeyType() const {
1231 DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1232 IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()) ||
1233 IsStoreDataPropertyInLiteralKind(kind()));
1234 auto pair = GetFeedbackPair();
1235 MaybeObject feedback = pair.first;
1236 if (feedback == MegamorphicSentinel()) {
1237 return static_cast<IcCheckType>(
1238 Smi::ToInt(pair.second->template cast<Object>()));
1239 }
1240 MaybeObject maybe_name =
1241 IsStoreDataPropertyInLiteralKind(kind()) ? pair.second : feedback;
1242 return IsPropertyNameFeedback(maybe_name) ? PROPERTY : ELEMENT;
1243 }
1244
GetBinaryOperationFeedback() const1245 BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
1246 DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1247 int feedback = GetFeedback().ToSmi().value();
1248 return BinaryOperationHintFromFeedback(feedback);
1249 }
1250
GetCompareOperationFeedback() const1251 CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
1252 DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1253 int feedback = GetFeedback().ToSmi().value();
1254 return CompareOperationHintFromFeedback(feedback);
1255 }
1256
GetForInFeedback() const1257 ForInHint FeedbackNexus::GetForInFeedback() const {
1258 DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1259 int feedback = GetFeedback().ToSmi().value();
1260 return ForInHintFromFeedback(static_cast<ForInFeedback>(feedback));
1261 }
1262
GetConstructorFeedback() const1263 MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
1264 DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1265 MaybeObject feedback = GetFeedback();
1266 HeapObject heap_object;
1267 if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1268 return config()->NewHandle(JSObject::cast(heap_object));
1269 }
1270 return MaybeHandle<JSObject>();
1271 }
1272
1273 namespace {
1274
InList(Handle<ArrayList> types,Handle<String> type)1275 bool InList(Handle<ArrayList> types, Handle<String> type) {
1276 for (int i = 0; i < types->Length(); i++) {
1277 Object obj = types->Get(i);
1278 if (String::cast(obj).Equals(*type)) {
1279 return true;
1280 }
1281 }
1282 return false;
1283 }
1284 } // anonymous namespace
1285
Collect(Handle<String> type,int position)1286 void FeedbackNexus::Collect(Handle<String> type, int position) {
1287 DCHECK(IsTypeProfileKind(kind()));
1288 DCHECK_GE(position, 0);
1289 DCHECK(config()->can_write());
1290 Isolate* isolate = GetIsolate();
1291
1292 MaybeObject const feedback = GetFeedback();
1293
1294 // Map source position to collection of types
1295 Handle<SimpleNumberDictionary> types;
1296
1297 if (feedback == UninitializedSentinel()) {
1298 types = SimpleNumberDictionary::New(isolate, 1);
1299 } else {
1300 types = handle(
1301 SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1302 isolate);
1303 }
1304
1305 Handle<ArrayList> position_specific_types;
1306
1307 InternalIndex entry = types->FindEntry(isolate, position);
1308 if (entry.is_not_found()) {
1309 position_specific_types = ArrayList::New(isolate, 1);
1310 types = SimpleNumberDictionary::Set(
1311 isolate, types, position,
1312 ArrayList::Add(isolate, position_specific_types, type));
1313 } else {
1314 DCHECK(types->ValueAt(entry).IsArrayList());
1315 position_specific_types =
1316 handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1317 if (!InList(position_specific_types, type)) { // Add type
1318 types = SimpleNumberDictionary::Set(
1319 isolate, types, position,
1320 ArrayList::Add(isolate, position_specific_types, type));
1321 }
1322 }
1323 SetFeedback(*types);
1324 }
1325
GetSourcePositions() const1326 std::vector<int> FeedbackNexus::GetSourcePositions() const {
1327 DCHECK(IsTypeProfileKind(kind()));
1328 std::vector<int> source_positions;
1329 Isolate* isolate = GetIsolate();
1330
1331 MaybeObject const feedback = GetFeedback();
1332
1333 if (feedback == UninitializedSentinel()) {
1334 return source_positions;
1335 }
1336
1337 Handle<SimpleNumberDictionary> types(
1338 SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1339 isolate);
1340
1341 for (int index = SimpleNumberDictionary::kElementsStartIndex;
1342 index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
1343 int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1344 Object key = types->get(key_index);
1345 if (key.IsSmi()) {
1346 int position = Smi::cast(key).value();
1347 source_positions.push_back(position);
1348 }
1349 }
1350 return source_positions;
1351 }
1352
GetTypesForSourcePositions(uint32_t position) const1353 std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1354 uint32_t position) const {
1355 DCHECK(IsTypeProfileKind(kind()));
1356 Isolate* isolate = GetIsolate();
1357
1358 MaybeObject const feedback = GetFeedback();
1359 std::vector<Handle<String>> types_for_position;
1360 if (feedback == UninitializedSentinel()) {
1361 return types_for_position;
1362 }
1363
1364 Handle<SimpleNumberDictionary> types(
1365 SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1366 isolate);
1367
1368 InternalIndex entry = types->FindEntry(isolate, position);
1369 if (entry.is_not_found()) return types_for_position;
1370
1371 DCHECK(types->ValueAt(entry).IsArrayList());
1372 Handle<ArrayList> position_specific_types =
1373 Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1374 for (int i = 0; i < position_specific_types->Length(); i++) {
1375 Object t = position_specific_types->Get(i);
1376 types_for_position.push_back(Handle<String>(String::cast(t), isolate));
1377 }
1378
1379 return types_for_position;
1380 }
1381
1382 namespace {
1383
ConvertToJSObject(Isolate * isolate,Handle<SimpleNumberDictionary> feedback)1384 Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1385 Handle<SimpleNumberDictionary> feedback) {
1386 Handle<JSObject> type_profile =
1387 isolate->factory()->NewJSObject(isolate->object_function());
1388
1389 for (int index = SimpleNumberDictionary::kElementsStartIndex;
1390 index < feedback->length();
1391 index += SimpleNumberDictionary::kEntrySize) {
1392 int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1393 Object key = feedback->get(key_index);
1394 if (key.IsSmi()) {
1395 int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1396
1397 Handle<ArrayList> position_specific_types(
1398 ArrayList::cast(feedback->get(value_index)), isolate);
1399
1400 int position = Smi::ToInt(key);
1401 JSObject::AddDataElement(
1402 type_profile, position,
1403 isolate->factory()->NewJSArrayWithElements(
1404 ArrayList::Elements(isolate, position_specific_types)),
1405 PropertyAttributes::NONE);
1406 }
1407 }
1408 return type_profile;
1409 }
1410 } // namespace
1411
GetTypeProfile() const1412 JSObject FeedbackNexus::GetTypeProfile() const {
1413 DCHECK(IsTypeProfileKind(kind()));
1414 Isolate* isolate = GetIsolate();
1415
1416 MaybeObject const feedback = GetFeedback();
1417
1418 if (feedback == UninitializedSentinel()) {
1419 return *isolate->factory()->NewJSObject(isolate->object_function());
1420 }
1421
1422 return *ConvertToJSObject(isolate,
1423 handle(SimpleNumberDictionary::cast(
1424 feedback->GetHeapObjectAssumeStrong()),
1425 isolate));
1426 }
1427
ResetTypeProfile()1428 void FeedbackNexus::ResetTypeProfile() {
1429 DCHECK(IsTypeProfileKind(kind()));
1430 SetFeedback(UninitializedSentinel());
1431 }
1432
FeedbackIterator(const FeedbackNexus * nexus)1433 FeedbackIterator::FeedbackIterator(const FeedbackNexus* nexus)
1434 : done_(false), index_(-1), state_(kOther) {
1435 DCHECK(IsLoadICKind(nexus->kind()) ||
1436 IsStoreICKind(nexus->kind()) | IsKeyedLoadICKind(nexus->kind()) ||
1437 IsKeyedStoreICKind(nexus->kind()) || IsStoreOwnICKind(nexus->kind()) ||
1438 IsStoreDataPropertyInLiteralKind(nexus->kind()) ||
1439 IsStoreInArrayLiteralICKind(nexus->kind()) ||
1440 IsKeyedHasICKind(nexus->kind()));
1441
1442 DisallowHeapAllocation no_gc;
1443 auto pair = nexus->GetFeedbackPair();
1444 MaybeObject feedback = pair.first;
1445 bool is_named_feedback = IsPropertyNameFeedback(feedback);
1446 HeapObject heap_object;
1447
1448 if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1449 heap_object.IsWeakFixedArray()) ||
1450 is_named_feedback) {
1451 index_ = 0;
1452 state_ = kPolymorphic;
1453 heap_object = feedback->GetHeapObjectAssumeStrong();
1454 if (is_named_feedback) {
1455 polymorphic_feedback_ = nexus->config()->NewHandle(
1456 WeakFixedArray::cast(pair.second->GetHeapObjectAssumeStrong()));
1457 } else {
1458 polymorphic_feedback_ =
1459 nexus->config()->NewHandle(WeakFixedArray::cast(heap_object));
1460 }
1461 AdvancePolymorphic();
1462 } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1463 state_ = kMonomorphic;
1464 MaybeObject handler = pair.second;
1465 map_ = Map::cast(heap_object);
1466 handler_ = handler;
1467 } else {
1468 done_ = true;
1469 }
1470 }
1471
Advance()1472 void FeedbackIterator::Advance() {
1473 CHECK(!done_);
1474
1475 if (state_ == kMonomorphic) {
1476 done_ = true;
1477 return;
1478 }
1479
1480 CHECK_EQ(state_, kPolymorphic);
1481 AdvancePolymorphic();
1482 }
1483
AdvancePolymorphic()1484 void FeedbackIterator::AdvancePolymorphic() {
1485 CHECK(!done_);
1486 CHECK_EQ(state_, kPolymorphic);
1487 int length = polymorphic_feedback_->length();
1488 HeapObject heap_object;
1489
1490 while (index_ < length) {
1491 if (polymorphic_feedback_->Get(index_)->GetHeapObjectIfWeak(&heap_object)) {
1492 MaybeObject handler = polymorphic_feedback_->Get(index_ + kHandlerOffset);
1493 map_ = Map::cast(heap_object);
1494 handler_ = handler;
1495 index_ += kEntrySize;
1496 return;
1497 }
1498 index_ += kEntrySize;
1499 }
1500
1501 CHECK_EQ(index_, length);
1502 done_ = true;
1503 }
1504 } // namespace internal
1505 } // namespace v8
1506