V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
ic.cc
1 // Copyright 2012 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/ic/ic.h"
6 
7 #include "src/accessors.h"
8 #include "src/api-arguments-inl.h"
9 #include "src/api.h"
10 #include "src/arguments-inl.h"
11 #include "src/ast/ast.h"
12 #include "src/base/bits.h"
13 #include "src/code-factory.h"
14 #include "src/conversions.h"
15 #include "src/execution.h"
16 #include "src/field-type.h"
17 #include "src/frames-inl.h"
18 #include "src/handles-inl.h"
19 #include "src/ic/call-optimization.h"
20 #include "src/ic/handler-configuration-inl.h"
21 #include "src/ic/ic-inl.h"
22 #include "src/ic/ic-stats.h"
23 #include "src/ic/stub-cache.h"
24 #include "src/isolate-inl.h"
25 #include "src/macro-assembler.h"
26 #include "src/objects/api-callbacks.h"
27 #include "src/objects/data-handler-inl.h"
28 #include "src/objects/hash-table-inl.h"
29 #include "src/objects/js-array-inl.h"
30 #include "src/objects/module-inl.h"
31 #include "src/prototype.h"
32 #include "src/runtime-profiler.h"
33 #include "src/runtime/runtime-utils.h"
34 #include "src/runtime/runtime.h"
35 #include "src/tracing/trace-event.h"
36 #include "src/tracing/tracing-category-observer.h"
37 
38 namespace v8 {
39 namespace internal {
40 
41 char IC::TransitionMarkFromState(IC::State state) {
42  switch (state) {
43  case UNINITIALIZED:
44  return '0';
45  case PREMONOMORPHIC:
46  return '.';
47  case MONOMORPHIC:
48  return '1';
49  case RECOMPUTE_HANDLER:
50  return '^';
51  case POLYMORPHIC:
52  return 'P';
53  case MEGAMORPHIC:
54  return 'N';
55  case GENERIC:
56  return 'G';
57  }
58  UNREACHABLE();
59 }
60 
61 namespace {
62 
63 const char* GetModifier(KeyedAccessLoadMode mode) {
64  if (mode == LOAD_IGNORE_OUT_OF_BOUNDS) return ".IGNORE_OOB";
65  return "";
66 }
67 
68 const char* GetModifier(KeyedAccessStoreMode mode) {
69  switch (mode) {
70  case STORE_NO_TRANSITION_HANDLE_COW:
71  return ".COW";
72  case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
73  return ".STORE+COW";
74  case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
75  return ".IGNORE_OOB";
76  default:
77  break;
78  }
79  DCHECK(!IsCOWHandlingStoreMode(mode));
80  return IsGrowStoreMode(mode) ? ".GROW" : "";
81 }
82 
83 } // namespace
84 
85 void IC::TraceIC(const char* type, Handle<Object> name) {
86  if (FLAG_ic_stats) {
87  if (AddressIsDeoptimizedCode()) return;
88  State new_state = nexus()->StateFromFeedback();
89  TraceIC(type, name, state(), new_state);
90  }
91 }
92 
93 void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
94  State new_state) {
95  if (V8_LIKELY(!FLAG_ic_stats)) return;
96 
97  Map map;
98  if (!receiver_map().is_null()) {
99  map = *receiver_map();
100  }
101 
102  const char* modifier = "";
103  if (IsKeyedLoadIC()) {
104  KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
105  modifier = GetModifier(mode);
106  } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind())) {
107  KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
108  modifier = GetModifier(mode);
109  }
110 
111  bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralICKind(kind());
112 
113  if (!(FLAG_ic_stats &
114  v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
115  LOG(isolate(), ICEvent(type, keyed_prefix, map, *name,
116  TransitionMarkFromState(old_state),
117  TransitionMarkFromState(new_state), modifier,
118  slow_stub_reason_));
119  return;
120  }
121 
122  ICStats::instance()->Begin();
123  ICInfo& ic_info = ICStats::instance()->Current();
124  ic_info.type = keyed_prefix ? "Keyed" : "";
125  ic_info.type += type;
126 
127  Object* maybe_function =
128  Memory<Object*>(fp_ + JavaScriptFrameConstants::kFunctionOffset);
129  DCHECK(maybe_function->IsJSFunction());
130  JSFunction* function = JSFunction::cast(maybe_function);
131  int code_offset = 0;
132  if (function->IsInterpreted()) {
133  code_offset = InterpretedFrame::GetBytecodeOffset(fp());
134  } else {
135  code_offset = static_cast<int>(pc() - function->code()->InstructionStart());
136  }
137  JavaScriptFrame::CollectFunctionAndOffsetForICStats(
138  function, function->abstract_code(), code_offset);
139 
140  // Reserve enough space for IC transition state, the longest length is 17.
141  ic_info.state.reserve(17);
142  ic_info.state = "(";
143  ic_info.state += TransitionMarkFromState(old_state);
144  ic_info.state += "->";
145  ic_info.state += TransitionMarkFromState(new_state);
146  ic_info.state += modifier;
147  ic_info.state += ")";
148  ic_info.map = reinterpret_cast<void*>(map.ptr());
149  if (!map.is_null()) {
150  ic_info.is_dictionary_map = map->is_dictionary_map();
151  ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
152  ic_info.instance_type = std::to_string(map->instance_type());
153  }
154  // TODO(lpy) Add name as key field in ICStats.
155  ICStats::instance()->End();
156 }
157 
158 IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
159  : isolate_(isolate),
160  vector_set_(false),
161  kind_(FeedbackSlotKind::kInvalid),
162  target_maps_set_(false),
163  slow_stub_reason_(nullptr),
164  nexus_(vector, slot) {
165  // To improve the performance of the (much used) IC code, we unfold a few
166  // levels of the stack frame iteration code. This yields a ~35% speedup when
167  // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
168  const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
169  Address* constant_pool = nullptr;
170  if (FLAG_enable_embedded_constant_pool) {
171  constant_pool = reinterpret_cast<Address*>(
172  entry + ExitFrameConstants::kConstantPoolOffset);
173  }
174  Address* pc_address =
175  reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
176  Address fp = Memory<Address>(entry + ExitFrameConstants::kCallerFPOffset);
177 #ifdef DEBUG
178  StackFrameIterator it(isolate);
179  for (int i = 0; i < 1; i++) it.Advance();
180  StackFrame* frame = it.frame();
181  DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
182 #endif
183  // For interpreted functions, some bytecode handlers construct a
184  // frame. We have to skip the constructed frame to find the interpreted
185  // function's frame. Check if the there is an additional frame, and if there
186  // is skip this frame. However, the pc should not be updated. The call to
187  // ICs happen from bytecode handlers.
188  intptr_t frame_marker =
189  Memory<intptr_t>(fp + TypedFrameConstants::kFrameTypeOffset);
190  if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
191  fp = Memory<Address>(fp + TypedFrameConstants::kCallerFPOffset);
192  }
193  fp_ = fp;
194  if (FLAG_enable_embedded_constant_pool) {
195  constant_pool_address_ = constant_pool;
196  }
197  pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
198  kind_ = nexus_.kind();
199  state_ = nexus_.StateFromFeedback();
200  old_state_ = state_;
201 }
202 
203 JSFunction* IC::GetHostFunction() const {
204  // Compute the JavaScript frame for the frame pointer of this IC
205  // structure. We need this to be able to find the function
206  // corresponding to the frame.
207  StackFrameIterator it(isolate());
208  while (it.frame()->fp() != this->fp()) it.Advance();
209  JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
210  // Find the function on the stack and both the active code for the
211  // function and the original code.
212  return frame->function();
213 }
214 
215 static void LookupForRead(Isolate* isolate, LookupIterator* it) {
216  for (; it->IsFound(); it->Next()) {
217  switch (it->state()) {
218  case LookupIterator::NOT_FOUND:
219  case LookupIterator::TRANSITION:
220  UNREACHABLE();
221  case LookupIterator::JSPROXY:
222  return;
223  case LookupIterator::INTERCEPTOR: {
224  // If there is a getter, return; otherwise loop to perform the lookup.
225  Handle<JSObject> holder = it->GetHolder<JSObject>();
226  if (!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate)) {
227  return;
228  }
229  break;
230  }
231  case LookupIterator::ACCESS_CHECK:
232  // ICs know how to perform access checks on global proxies.
233  if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
234  break;
235  }
236  return;
237  case LookupIterator::ACCESSOR:
238  case LookupIterator::INTEGER_INDEXED_EXOTIC:
239  case LookupIterator::DATA:
240  return;
241  }
242  }
243 }
244 
245 bool IC::ShouldRecomputeHandler(Handle<String> name) {
246  if (!RecomputeHandlerForName(name)) return false;
247 
248  // This is a contextual access, always just update the handler and stay
249  // monomorphic.
250  if (IsGlobalIC()) return true;
251 
252  maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
253 
254  // The current map wasn't handled yet. There's no reason to stay monomorphic,
255  // *unless* we're moving from a deprecated map to its replacement, or
256  // to a more general elements kind.
257  // TODO(verwaest): Check if the current map is actually what the old map
258  // would transition to.
259  if (maybe_handler_.is_null()) {
260  if (!receiver_map()->IsJSObjectMap()) return false;
261  Map first_map = FirstTargetMap();
262  if (first_map.is_null()) return false;
263  Handle<Map> old_map(first_map, isolate());
264  if (old_map->is_deprecated()) return true;
265  return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
266  receiver_map()->elements_kind());
267  }
268 
269  return true;
270 }
271 
272 bool IC::RecomputeHandlerForName(Handle<Object> name) {
273  if (is_keyed()) {
274  // Determine whether the failure is due to a name failure.
275  if (!name->IsName()) return false;
276  Name stub_name = nexus()->FindFirstName();
277  if (*name != stub_name) return false;
278  }
279 
280  return true;
281 }
282 
283 
284 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
285  update_receiver_map(receiver);
286  if (!name->IsString()) return;
287  if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
288  if (receiver->IsNullOrUndefined(isolate())) return;
289 
290  // Remove the target from the code cache if it became invalid
291  // because of changes in the prototype chain to avoid hitting it
292  // again.
293  if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
294  MarkRecomputeHandler(name);
295  }
296 }
297 
298 MaybeHandle<Object> IC::TypeError(MessageTemplate index, Handle<Object> object,
299  Handle<Object> key) {
300  HandleScope scope(isolate());
301  THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
302 }
303 
304 
305 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
306  HandleScope scope(isolate());
307  THROW_NEW_ERROR(
308  isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
309 }
310 
311 // static
312 void IC::OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
313  JSFunction* host_function, const char* reason) {
314  FeedbackVector* vector = nexus->vector();
315  FeedbackSlot slot = nexus->slot();
316  OnFeedbackChanged(isolate, vector, slot, host_function, reason);
317 }
318 
319 // static
320 void IC::OnFeedbackChanged(Isolate* isolate, FeedbackVector* vector,
321  FeedbackSlot slot, JSFunction* host_function,
322  const char* reason) {
323  if (FLAG_trace_opt_verbose) {
324  // TODO(leszeks): The host function is only needed for this print, we could
325  // remove it as a parameter if we're of with removing this trace (or only
326  // tracing the feedback vector, not the function name).
327  if (vector->profiler_ticks() != 0) {
328  PrintF("[resetting ticks for ");
329  host_function->ShortPrint();
330  PrintF(" due from %d due to IC change: %s]\n", vector->profiler_ticks(),
331  reason);
332  }
333  }
334  vector->set_profiler_ticks(0);
335 
336 #ifdef V8_TRACE_FEEDBACK_UPDATES
337  if (FLAG_trace_feedback_updates) {
338  int slot_count = vector->metadata()->slot_count();
339 
340  StdoutStream os;
341  if (slot.IsInvalid()) {
342  os << "[Feedback slots in ";
343  } else {
344  os << "[Feedback slot " << slot.ToInt() << "/" << slot_count << " in ";
345  }
346  vector->shared_function_info()->ShortPrint(os);
347  if (slot.IsInvalid()) {
348  os << " updated - ";
349  } else {
350  os << " updated to ";
351  vector->FeedbackSlotPrint(os, slot);
352  os << " - ";
353  }
354  os << reason << "]" << std::endl;
355  }
356 #endif
357 
358  isolate->runtime_profiler()->NotifyICChanged();
359  // TODO(2029): When an optimized function is patched, it would
360  // be nice to propagate the corresponding type information to its
361  // unoptimized version for the benefit of later inlining.
362 }
363 
364 static bool MigrateDeprecated(Handle<Object> object) {
365  if (!object->IsJSObject()) return false;
366  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
367  if (!receiver->map()->is_deprecated()) return false;
368  JSObject::MigrateInstance(Handle<JSObject>::cast(object));
369  return true;
370 }
371 
372 bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
373  DCHECK_EQ(MEGAMORPHIC, new_state);
374  DCHECK_IMPLIES(!is_keyed(), key->IsName());
375  // Even though we don't change the feedback data, we still want to reset the
376  // profiler ticks. Real-world observations suggest that optimizing these
377  // functions doesn't improve performance.
378  bool changed =
379  nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT);
380  vector_set_ = true;
381  OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Megamorphic");
382  return changed;
383 }
384 
385 void IC::ConfigureVectorState(Handle<Map> map) {
386  nexus()->ConfigurePremonomorphic(map);
387  vector_set_ = true;
388  OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Premonomorphic");
389 }
390 
391 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
392  Handle<Object> handler) {
393  ConfigureVectorState(name, map, MaybeObjectHandle(handler));
394 }
395 
396 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
397  const MaybeObjectHandle& handler) {
398  if (IsGlobalIC()) {
399  nexus()->ConfigureHandlerMode(handler);
400  } else {
401  // Non-keyed ICs don't track the name explicitly.
402  if (!is_keyed()) name = Handle<Name>::null();
403  nexus()->ConfigureMonomorphic(name, map, handler);
404  }
405 
406  vector_set_ = true;
407  OnFeedbackChanged(isolate(), nexus(), GetHostFunction(),
408  IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic");
409 }
410 
411 void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
412  MaybeObjectHandles* handlers) {
413  DCHECK(!IsGlobalIC());
414  // Non-keyed ICs don't track the name explicitly.
415  if (!is_keyed()) name = Handle<Name>::null();
416  nexus()->ConfigurePolymorphic(name, maps, handlers);
417 
418  vector_set_ = true;
419  OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Polymorphic");
420 }
421 
422 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
423  // If the object is undefined or null it's illegal to try to get any
424  // of its properties; throw a TypeError in that case.
425  if (object->IsNullOrUndefined(isolate())) {
426  if (FLAG_use_ic && state() != PREMONOMORPHIC) {
427  // Ensure the IC state progresses.
428  TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
429  update_receiver_map(object);
430  PatchCache(name, slow_stub());
431  TraceIC("LoadIC", name);
432  }
433 
434  if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
435  return Runtime::ThrowIteratorError(isolate(), object);
436  }
437  return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
438  }
439 
440  bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
441 
442  if (state() != UNINITIALIZED) {
443  JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
444  update_receiver_map(object);
445  }
446  // Named lookup in the object.
447  LookupIterator it(isolate(), object, name);
448  LookupForRead(isolate(), &it);
449 
450  if (name->IsPrivate()) {
451  if (name->IsPrivateName() && !it.IsFound()) {
452  return TypeError(MessageTemplate::kInvalidPrivateFieldAccess, object,
453  name);
454  }
455 
456  // IC handling of private symbols/fields lookup on JSProxy is not
457  // supported.
458  if (object->IsJSProxy()) {
459  use_ic = false;
460  }
461  }
462 
463  if (it.IsFound() || !ShouldThrowReferenceError()) {
464  // Update inline cache and stub cache.
465  if (use_ic) UpdateCaches(&it);
466 
467  // Get the property.
468  Handle<Object> result;
469 
470  ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
471  Object);
472  if (it.IsFound()) {
473  return result;
474  } else if (!ShouldThrowReferenceError()) {
475  LOG(isolate(), SuspectReadEvent(*name, *object));
476  return result;
477  }
478  }
479  return ReferenceError(name);
480 }
481 
482 MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
483  Handle<JSGlobalObject> global = isolate()->global_object();
484 
485  if (name->IsString()) {
486  // Look up in script context table.
487  Handle<String> str_name = Handle<String>::cast(name);
488  Handle<ScriptContextTable> script_contexts(
489  global->native_context()->script_context_table(), isolate());
490 
491  ScriptContextTable::LookupResult lookup_result;
492  if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
493  &lookup_result)) {
494  Handle<Context> script_context = ScriptContextTable::GetContext(
495  isolate(), script_contexts, lookup_result.context_index);
496 
497  Handle<Object> result(script_context->get(lookup_result.slot_index),
498  isolate());
499 
500  if (result->IsTheHole(isolate())) {
501  // Do not install stubs and stay pre-monomorphic for
502  // uninitialized accesses.
503  return ReferenceError(name);
504  }
505 
506  if (FLAG_use_ic) {
507  if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
508  lookup_result.slot_index)) {
509  TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
510  } else {
511  // Given combination of indices can't be encoded, so use slow stub.
512  TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
513  PatchCache(name, slow_stub());
514  }
515  TraceIC("LoadGlobalIC", name);
516  }
517  return result;
518  }
519  }
520  return LoadIC::Load(global, name);
521 }
522 
523 static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
524  Handle<Map> new_receiver_map) {
525  DCHECK(!new_receiver_map.is_null());
526  for (Handle<Map> map : *receiver_maps) {
527  if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
528  return false;
529  }
530  }
531  receiver_maps->push_back(new_receiver_map);
532  return true;
533 }
534 
535 bool IC::UpdatePolymorphicIC(Handle<Name> name,
536  const MaybeObjectHandle& handler) {
537  DCHECK(IsHandler(*handler));
538  if (is_keyed() && state() != RECOMPUTE_HANDLER) {
539  if (nexus()->FindFirstName() != *name) return false;
540  }
541  Handle<Map> map = receiver_map();
542  MapHandles maps;
543  MaybeObjectHandles handlers;
544 
545  TargetMaps(&maps);
546  int number_of_maps = static_cast<int>(maps.size());
547  int deprecated_maps = 0;
548  int handler_to_overwrite = -1;
549  if (!nexus()->FindHandlers(&handlers, number_of_maps)) return false;
550 
551  for (int i = 0; i < number_of_maps; i++) {
552  Handle<Map> current_map = maps.at(i);
553  if (current_map->is_deprecated()) {
554  // Filter out deprecated maps to ensure their instances get migrated.
555  ++deprecated_maps;
556  } else if (map.is_identical_to(current_map)) {
557  // If both map and handler stayed the same (and the name is also the
558  // same as checked above, for keyed accesses), we're not progressing
559  // in the lattice and need to go MEGAMORPHIC instead. There's one
560  // exception to this rule, which is when we're in RECOMPUTE_HANDLER
561  // state, there we allow to migrate to a new handler.
562  if (handler.is_identical_to(handlers[i]) &&
563  state() != RECOMPUTE_HANDLER) {
564  return false;
565  }
566  // If the receiver type is already in the polymorphic IC, this indicates
567  // there was a prototoype chain failure. In that case, just overwrite the
568  // handler.
569  handler_to_overwrite = i;
570  } else if (handler_to_overwrite == -1 &&
571  IsTransitionOfMonomorphicTarget(*current_map, *map)) {
572  handler_to_overwrite = i;
573  }
574  }
575 
576  int number_of_valid_maps =
577  number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
578 
579  if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
580  if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
581  return false;
582  }
583 
584  number_of_valid_maps++;
585  if (number_of_valid_maps == 1) {
586  ConfigureVectorState(name, receiver_map(), handler);
587  } else {
588  if (is_keyed() && nexus()->FindFirstName() != *name) return false;
589  if (handler_to_overwrite >= 0) {
590  handlers[handler_to_overwrite] = handler;
591  if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
592  maps[handler_to_overwrite] = map;
593  }
594  } else {
595  maps.push_back(map);
596  handlers.push_back(handler);
597  }
598 
599  ConfigureVectorState(name, maps, &handlers);
600  }
601 
602  return true;
603 }
604 
605 void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
606  Handle<Name> name) {
607  DCHECK(IsHandler(*handler));
608  ConfigureVectorState(name, receiver_map(), handler);
609 }
610 
611 
612 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
613  MapHandles maps;
614  MaybeObjectHandles handlers;
615  TargetMaps(&maps);
616  if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) return;
617  for (int i = 0; i < static_cast<int>(maps.size()); i++) {
618  UpdateMegamorphicCache(maps.at(i), name, handlers.at(i));
619  }
620 }
621 
622 bool IC::IsTransitionOfMonomorphicTarget(Map source_map, Map target_map) {
623  if (source_map.is_null()) return true;
624  if (target_map.is_null()) return false;
625  if (source_map->is_abandoned_prototype_map()) return false;
626  ElementsKind target_elements_kind = target_map->elements_kind();
627  bool more_general_transition = IsMoreGeneralElementsKindTransition(
628  source_map->elements_kind(), target_elements_kind);
629  Map transitioned_map;
630  if (more_general_transition) {
631  MapHandles map_list;
632  map_list.push_back(handle(target_map, isolate_));
633  transitioned_map =
634  source_map->FindElementsKindTransitionedMap(isolate(), map_list);
635  }
636  return transitioned_map == target_map;
637 }
638 
639 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
640  PatchCache(name, MaybeObjectHandle(handler));
641 }
642 
643 void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
644  DCHECK(IsHandler(*handler));
645  // Currently only load and store ICs support non-code handlers.
646  DCHECK(IsAnyLoad() || IsAnyStore());
647  switch (state()) {
648  case UNINITIALIZED:
649  case PREMONOMORPHIC:
650  UpdateMonomorphicIC(handler, name);
651  break;
652  case RECOMPUTE_HANDLER:
653  case MONOMORPHIC:
654  if (IsGlobalIC()) {
655  UpdateMonomorphicIC(handler, name);
656  break;
657  }
658  V8_FALLTHROUGH;
659  case POLYMORPHIC:
660  if (UpdatePolymorphicIC(name, handler)) break;
661  if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
662  CopyICToMegamorphicCache(name);
663  }
664  ConfigureVectorState(MEGAMORPHIC, name);
665  V8_FALLTHROUGH;
666  case MEGAMORPHIC:
667  UpdateMegamorphicCache(receiver_map(), name, handler);
668  // Indicate that we've handled this case.
669  vector_set_ = true;
670  break;
671  case GENERIC:
672  UNREACHABLE();
673  break;
674  }
675 }
676 
677 void LoadIC::UpdateCaches(LookupIterator* lookup) {
678  if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
679  // This is the first time we execute this inline cache. Set the target to
680  // the pre monomorphic stub to delay setting the monomorphic state.
681  TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
682  ConfigureVectorState(receiver_map());
683  TraceIC("LoadIC", lookup->name());
684  return;
685  }
686 
687  Handle<Object> code;
688  if (lookup->state() == LookupIterator::ACCESS_CHECK) {
689  code = slow_stub();
690  } else if (!lookup->IsFound()) {
691  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
692  Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
693  code = LoadHandler::LoadFullChain(
694  isolate(), receiver_map(),
695  MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
696  } else {
697  if (IsLoadGlobalIC()) {
698  if (lookup->TryLookupCachedProperty()) {
699  DCHECK_EQ(LookupIterator::DATA, lookup->state());
700  }
701  if (lookup->state() == LookupIterator::DATA &&
702  lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
703  DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
704  // Now update the cell in the feedback vector.
705  nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
706  TraceIC("LoadGlobalIC", lookup->name());
707  return;
708  }
709  }
710  code = ComputeHandler(lookup);
711  }
712 
713  PatchCache(lookup->name(), code);
714  TraceIC("LoadIC", lookup->name());
715 }
716 
717 StubCache* IC::stub_cache() {
718  if (IsAnyLoad()) {
719  return isolate()->load_stub_cache();
720  } else {
721  DCHECK(IsAnyStore());
722  return isolate()->store_stub_cache();
723  }
724 }
725 
726 void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
727  const MaybeObjectHandle& handler) {
728  stub_cache()->Set(*name, *map, *handler);
729 }
730 
731 void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
732  DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
733  if (V8_LIKELY(!FLAG_runtime_stats)) return;
734  if (IsAnyLoad()) {
735  TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
736  } else {
737  DCHECK(IsAnyStore());
738  TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
739  }
740 }
741 
742 Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
743  Handle<Object> receiver = lookup->GetReceiver();
744  ReadOnlyRoots roots(isolate());
745  if (receiver->IsString() && *lookup->name() == roots.length_string()) {
746  TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
747  return BUILTIN_CODE(isolate(), LoadIC_StringLength);
748  }
749 
750  if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) {
751  TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
752  return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength);
753  }
754 
755  // Use specialized code for getting prototype of functions.
756  if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() &&
757  !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) {
758  Handle<Code> stub;
759  TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
760  return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype);
761  }
762 
763  Handle<Map> map = receiver_map();
764  Handle<JSObject> holder;
765  bool receiver_is_holder;
766  if (lookup->state() != LookupIterator::JSPROXY) {
767  holder = lookup->GetHolder<JSObject>();
768  receiver_is_holder = receiver.is_identical_to(holder);
769  }
770 
771  switch (lookup->state()) {
772  case LookupIterator::INTERCEPTOR: {
773  Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
774 
775  if (holder->GetNamedInterceptor()->non_masking()) {
776  MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
777  if (!receiver_is_holder || IsLoadGlobalIC()) {
778  holder_ref = MaybeObjectHandle::Weak(holder);
779  }
780  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
781  return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
782  smi_handler);
783  }
784 
785  if (receiver_is_holder) {
786  DCHECK(map->has_named_interceptor());
787  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
788  return smi_handler;
789  }
790 
791  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
792  return LoadHandler::LoadFromPrototype(isolate(), map, holder,
793  smi_handler);
794  }
795 
796  case LookupIterator::ACCESSOR: {
797  // Use simple field loads for some well-known callback properties.
798  // The method will only return true for absolute truths based on the
799  // receiver maps.
800  FieldIndex index;
801  if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
802  &index)) {
803  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
804  return LoadHandler::LoadField(isolate(), index);
805  }
806  if (holder->IsJSModuleNamespace()) {
807  Handle<ObjectHashTable> exports(
808  Handle<JSModuleNamespace>::cast(holder)->module()->exports(),
809  isolate());
810  int entry = exports->FindEntry(roots, lookup->name(),
811  Smi::ToInt(lookup->name()->GetHash()));
812  // We found the accessor, so the entry must exist.
813  DCHECK_NE(entry, ObjectHashTable::kNotFound);
814  int index = ObjectHashTable::EntryToValueIndex(entry);
815  return LoadHandler::LoadModuleExport(isolate(), index);
816  }
817 
818  Handle<Object> accessors = lookup->GetAccessors();
819  if (accessors->IsAccessorPair()) {
820  if (lookup->TryLookupCachedProperty()) {
821  DCHECK_EQ(LookupIterator::DATA, lookup->state());
822  return ComputeHandler(lookup);
823  }
824 
825  Handle<Object> getter(AccessorPair::cast(*accessors)->getter(),
826  isolate());
827  if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
828  TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
829  return slow_stub();
830  }
831 
832  if (getter->IsFunctionTemplateInfo() &&
833  FunctionTemplateInfo::cast(*getter)->BreakAtEntry()) {
834  // Do not install an IC if the api function has a breakpoint.
835  TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
836  return slow_stub();
837  }
838 
839  Handle<Smi> smi_handler;
840 
841  CallOptimization call_optimization(isolate(), getter);
842  if (call_optimization.is_simple_api_call()) {
843  if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
844  !holder->HasFastProperties()) {
845  TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
846  return slow_stub();
847  }
848 
849  CallOptimization::HolderLookup holder_lookup;
850  call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
851 
852  smi_handler = LoadHandler::LoadApiGetter(
853  isolate(), holder_lookup == CallOptimization::kHolderIsReceiver);
854 
855  Handle<Context> context(
856  call_optimization.GetAccessorContext(holder->map()), isolate());
857 
858  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
859  return LoadHandler::LoadFromPrototype(
860  isolate(), map, holder, smi_handler,
861  MaybeObjectHandle::Weak(call_optimization.api_call_info()),
862  MaybeObjectHandle::Weak(context));
863  }
864 
865  if (holder->HasFastProperties()) {
866  smi_handler =
867  LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
868 
869  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
870  if (receiver_is_holder) return smi_handler;
871  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
872  } else if (holder->IsJSGlobalObject()) {
873  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
874  smi_handler = LoadHandler::LoadGlobal(isolate());
875  return LoadHandler::LoadFromPrototype(
876  isolate(), map, holder, smi_handler,
877  MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
878  } else {
879  smi_handler = LoadHandler::LoadNormal(isolate());
880 
881  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
882  if (receiver_is_holder) return smi_handler;
883  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
884  }
885 
886  return LoadHandler::LoadFromPrototype(isolate(), map, holder,
887  smi_handler);
888  }
889 
890  Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
891 
892  if (v8::ToCData<Address>(info->getter()) == kNullAddress ||
893  !AccessorInfo::IsCompatibleReceiverMap(info, map) ||
894  !holder->HasFastProperties() ||
895  (info->is_sloppy() && !receiver->IsJSReceiver())) {
896  TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
897  return slow_stub();
898  }
899 
900  Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
901  isolate(), lookup->GetAccessorIndex());
902  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
903  if (receiver_is_holder) return smi_handler;
904  TRACE_HANDLER_STATS(isolate(),
905  LoadIC_LoadNativeDataPropertyFromPrototypeDH);
906  return LoadHandler::LoadFromPrototype(isolate(), map, holder,
907  smi_handler);
908  }
909 
910  case LookupIterator::DATA: {
911  DCHECK_EQ(kData, lookup->property_details().kind());
912  Handle<Smi> smi_handler;
913  if (lookup->is_dictionary_holder()) {
914  if (holder->IsJSGlobalObject()) {
915  // TODO(verwaest): Also supporting the global object as receiver is a
916  // workaround for code that leaks the global object.
917  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
918  smi_handler = LoadHandler::LoadGlobal(isolate());
919  return LoadHandler::LoadFromPrototype(
920  isolate(), map, holder, smi_handler,
921  MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
922  }
923 
924  smi_handler = LoadHandler::LoadNormal(isolate());
925  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
926  if (receiver_is_holder) return smi_handler;
927  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
928 
929  } else if (lookup->property_details().location() == kField) {
930  FieldIndex field = lookup->GetFieldIndex();
931  smi_handler = LoadHandler::LoadField(isolate(), field);
932  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
933  if (receiver_is_holder) return smi_handler;
934  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
935  } else {
936  DCHECK_EQ(kDescriptor, lookup->property_details().location());
937  smi_handler =
938  LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
939  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
940  if (receiver_is_holder) return smi_handler;
941  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
942  }
943  return LoadHandler::LoadFromPrototype(isolate(), map, holder,
944  smi_handler);
945  }
946  case LookupIterator::INTEGER_INDEXED_EXOTIC:
947  TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
948  return LoadHandler::LoadNonExistent(isolate());
949  case LookupIterator::JSPROXY: {
950  Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
951  bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy);
952  Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
953  if (receiver_is_holder_proxy) {
954  return smi_handler;
955  }
956  return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
957  smi_handler);
958  }
959  case LookupIterator::ACCESS_CHECK:
960  case LookupIterator::NOT_FOUND:
961  case LookupIterator::TRANSITION:
962  UNREACHABLE();
963  }
964 
965  return Handle<Code>::null();
966 }
967 
968 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
969  // This helper implements a few common fast cases for converting
970  // non-smi keys of keyed loads/stores to a smi or a string.
971  if (key->IsHeapNumber()) {
972  double value = Handle<HeapNumber>::cast(key)->value();
973  if (std::isnan(value)) {
974  key = isolate->factory()->NaN_string();
975  } else {
976  // Check bounds first to avoid undefined behavior in the conversion
977  // to int.
978  if (value <= Smi::kMaxValue && value >= Smi::kMinValue) {
979  int int_value = FastD2I(value);
980  if (value == int_value) {
981  key = handle(Smi::FromInt(int_value), isolate);
982  }
983  }
984  }
985  } else if (key->IsString()) {
986  key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
987  }
988  return key;
989 }
990 
991 bool KeyedLoadIC::CanChangeToAllowOutOfBounds(Handle<Map> receiver_map) {
992  const MaybeObjectHandle& handler = nexus()->FindHandlerForMap(receiver_map);
993  if (handler.is_null()) return false;
994  return LoadHandler::GetKeyedAccessLoadMode(*handler) == STANDARD_LOAD;
995 }
996 
997 void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
998  KeyedAccessLoadMode load_mode) {
999  Handle<Map> receiver_map(receiver->map(), isolate());
1000  DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller.
1001  MapHandles target_receiver_maps;
1002  TargetMaps(&target_receiver_maps);
1003 
1004  if (target_receiver_maps.empty()) {
1005  Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1006  return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1007  }
1008 
1009  for (Handle<Map> map : target_receiver_maps) {
1010  if (map.is_null()) continue;
1011  if (map->instance_type() == JS_VALUE_TYPE) {
1012  set_slow_stub_reason("JSValue");
1013  return;
1014  }
1015  if (map->instance_type() == JS_PROXY_TYPE) {
1016  set_slow_stub_reason("JSProxy");
1017  return;
1018  }
1019  }
1020 
1021  // The first time a receiver is seen that is a transitioned version of the
1022  // previous monomorphic receiver type, assume the new ElementsKind is the
1023  // monomorphic type. This benefits global arrays that only transition
1024  // once, and all call sites accessing them are faster if they remain
1025  // monomorphic. If this optimistic assumption is not true, the IC will
1026  // miss again and it will become polymorphic and support both the
1027  // untransitioned and transitioned maps.
1028  if (state() == MONOMORPHIC && !receiver->IsString() &&
1029  !receiver->IsJSProxy() &&
1030  IsMoreGeneralElementsKindTransition(
1031  target_receiver_maps.at(0)->elements_kind(),
1032  Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1033  Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1034  return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1035  }
1036 
1037  DCHECK(state() != GENERIC);
1038 
1039  // Determine the list of receiver maps that this call site has seen,
1040  // adding the map that was just encountered.
1041  if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1042  // If the {receiver_map} previously had a handler that didn't handle
1043  // out-of-bounds access, but can generally handle it, we can just go
1044  // on and update the handler appropriately below.
1045  if (load_mode != LOAD_IGNORE_OUT_OF_BOUNDS ||
1046  !CanChangeToAllowOutOfBounds(receiver_map)) {
1047  // If the miss wasn't due to an unseen map, a polymorphic stub
1048  // won't help, use the generic stub.
1049  set_slow_stub_reason("same map added twice");
1050  return;
1051  }
1052  }
1053 
1054  // If the maximum number of receiver maps has been exceeded, use the generic
1055  // version of the IC.
1056  if (target_receiver_maps.size() > kMaxKeyedPolymorphism) {
1057  set_slow_stub_reason("max polymorph exceeded");
1058  return;
1059  }
1060 
1061  MaybeObjectHandles handlers;
1062  handlers.reserve(target_receiver_maps.size());
1063  LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode);
1064  DCHECK_LE(1, target_receiver_maps.size());
1065  if (target_receiver_maps.size() == 1) {
1066  ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1067  } else {
1068  ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1069  }
1070 }
1071 
1072 Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
1073  KeyedAccessLoadMode load_mode) {
1074  if (receiver_map->has_indexed_interceptor() &&
1075  !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
1076  isolate()) &&
1077  !receiver_map->GetIndexedInterceptor()->non_masking()) {
1078  // TODO(jgruber): Update counter name.
1079  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1080  return BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
1081  }
1082  InstanceType instance_type = receiver_map->instance_type();
1083  if (instance_type < FIRST_NONSTRING_TYPE) {
1084  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
1085  return LoadHandler::LoadIndexedString(isolate(), load_mode);
1086  }
1087  if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1088  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1089  return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
1090  }
1091  if (instance_type == JS_PROXY_TYPE) {
1092  return LoadHandler::LoadProxy(isolate());
1093  }
1094 
1095  ElementsKind elements_kind = receiver_map->elements_kind();
1096  if (IsSloppyArgumentsElementsKind(elements_kind)) {
1097  // TODO(jgruber): Update counter name.
1098  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1099  return BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments);
1100  }
1101  bool is_js_array = instance_type == JS_ARRAY_TYPE;
1102  if (elements_kind == DICTIONARY_ELEMENTS) {
1103  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1104  return LoadHandler::LoadElement(isolate(), elements_kind, false,
1105  is_js_array, load_mode);
1106  }
1107  DCHECK(IsFastElementsKind(elements_kind) ||
1108  IsFixedTypedArrayElementsKind(elements_kind));
1109  // TODO(jkummerow): Use IsHoleyOrDictionaryElementsKind(elements_kind).
1110  bool convert_hole_to_undefined =
1111  is_js_array && elements_kind == HOLEY_ELEMENTS &&
1112  *receiver_map ==
1113  isolate()->raw_native_context()->GetInitialJSArrayMap(elements_kind);
1114  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1115  return LoadHandler::LoadElement(isolate(), elements_kind,
1116  convert_hole_to_undefined, is_js_array,
1117  load_mode);
1118 }
1119 
1120 void KeyedLoadIC::LoadElementPolymorphicHandlers(
1121  MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1122  KeyedAccessLoadMode load_mode) {
1123  // Filter out deprecated maps to ensure their instances get migrated.
1124  receiver_maps->erase(
1125  std::remove_if(
1126  receiver_maps->begin(), receiver_maps->end(),
1127  [](const Handle<Map>& map) { return map->is_deprecated(); }),
1128  receiver_maps->end());
1129 
1130  for (Handle<Map> receiver_map : *receiver_maps) {
1131  // Mark all stable receiver maps that have elements kind transition map
1132  // among receiver_maps as unstable because the optimizing compilers may
1133  // generate an elements kind transition for this kind of receivers.
1134  if (receiver_map->is_stable()) {
1135  Map tmap = receiver_map->FindElementsKindTransitionedMap(isolate(),
1136  *receiver_maps);
1137  if (!tmap.is_null()) {
1138  receiver_map->NotifyLeafMapLayoutChange(isolate());
1139  }
1140  }
1141  handlers->push_back(
1142  MaybeObjectHandle(LoadElementHandler(receiver_map, load_mode)));
1143  }
1144 }
1145 
1146 namespace {
1147 
1148 bool ConvertKeyToIndex(Handle<Object> receiver, Handle<Object> key,
1149  uint32_t* index) {
1150  if (!FLAG_use_ic) return false;
1151  if (receiver->IsAccessCheckNeeded() || receiver->IsJSValue()) return false;
1152 
1153  // For regular JSReceiver or String receivers, the {key} must be a positive
1154  // array index.
1155  if (receiver->IsJSReceiver() || receiver->IsString()) {
1156  if (key->ToArrayIndex(index)) return true;
1157  }
1158  // For JSTypedArray receivers, we can also support negative keys, which we
1159  // just map into the [2**31, 2**32 - 1] range via a bit_cast. This is valid
1160  // because JSTypedArray::length is always a Smi, so such keys will always
1161  // be detected as OOB.
1162  if (receiver->IsJSTypedArray()) {
1163  int32_t signed_index;
1164  if (key->ToInt32(&signed_index)) {
1165  *index = bit_cast<uint32_t>(signed_index);
1166  return true;
1167  }
1168  }
1169  return false;
1170 }
1171 
1172 bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) {
1173  uint32_t length = 0;
1174  if (receiver->IsJSArray()) {
1175  JSArray::cast(*receiver)->length()->ToArrayLength(&length);
1176  } else if (receiver->IsString()) {
1177  length = String::cast(*receiver)->length();
1178  } else if (receiver->IsJSObject()) {
1179  length = JSObject::cast(*receiver)->elements()->length();
1180  } else {
1181  return false;
1182  }
1183  return index >= length;
1184 }
1185 
1186 KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver,
1187  uint32_t index) {
1188  if (IsOutOfBoundsAccess(receiver, index)) {
1189  if (receiver->IsJSTypedArray()) {
1190  // For JSTypedArray we never lookup elements in the prototype chain.
1191  return LOAD_IGNORE_OUT_OF_BOUNDS;
1192  }
1193 
1194  // For other {receiver}s we need to check the "no elements" protector.
1195  if (isolate->IsNoElementsProtectorIntact()) {
1196  if (receiver->IsString()) {
1197  // ToObject(receiver) will have the initial String.prototype.
1198  return LOAD_IGNORE_OUT_OF_BOUNDS;
1199  }
1200  if (receiver->IsJSObject()) {
1201  // For other JSObjects (including JSArrays) we can only continue if
1202  // the {receiver}s prototype is either the initial Object.prototype
1203  // or the initial Array.prototype, which are both guarded by the
1204  // "no elements" protector checked above.
1205  Handle<Object> receiver_prototype(
1206  JSObject::cast(*receiver)->map()->prototype(), isolate);
1207  if (isolate->IsInAnyContext(*receiver_prototype,
1208  Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
1209  isolate->IsInAnyContext(*receiver_prototype,
1210  Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
1211  return LOAD_IGNORE_OUT_OF_BOUNDS;
1212  }
1213  }
1214  }
1215  }
1216  return STANDARD_LOAD;
1217 }
1218 
1219 } // namespace
1220 
1221 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1222  Handle<Object> key) {
1223  if (MigrateDeprecated(object)) {
1224  Handle<Object> result;
1225  ASSIGN_RETURN_ON_EXCEPTION(
1226  isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1227  Object);
1228  return result;
1229  }
1230 
1231  Handle<Object> load_handle;
1232 
1233  // Check for non-string values that can be converted into an
1234  // internalized string directly or is representable as a smi.
1235  key = TryConvertKey(key, isolate());
1236 
1237  uint32_t index;
1238  if ((key->IsInternalizedString() &&
1239  !String::cast(*key)->AsArrayIndex(&index)) ||
1240  key->IsSymbol()) {
1241  ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1242  LoadIC::Load(object, Handle<Name>::cast(key)),
1243  Object);
1244  } else if (ConvertKeyToIndex(object, key, &index)) {
1245  KeyedAccessLoadMode load_mode = GetLoadMode(isolate(), object, index);
1246  UpdateLoadElement(Handle<HeapObject>::cast(object), load_mode);
1247  if (is_vector_set()) {
1248  TraceIC("LoadIC", key);
1249  }
1250  }
1251 
1252  if (vector_needs_update()) {
1253  ConfigureVectorState(MEGAMORPHIC, key);
1254  TraceIC("LoadIC", key);
1255  }
1256 
1257  if (!load_handle.is_null()) return load_handle;
1258 
1259  Handle<Object> result;
1260  ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1261  Runtime::GetObjectProperty(isolate(), object, key),
1262  Object);
1263  return result;
1264 }
1265 
1266 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1267  StoreOrigin store_origin) {
1268  // Disable ICs for non-JSObjects for now.
1269  Handle<Object> object = it->GetReceiver();
1270  if (object->IsJSProxy()) return true;
1271  if (!object->IsJSObject()) return false;
1272  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1273  DCHECK(!receiver->map()->is_deprecated());
1274 
1275  if (it->state() != LookupIterator::TRANSITION) {
1276  for (; it->IsFound(); it->Next()) {
1277  switch (it->state()) {
1278  case LookupIterator::NOT_FOUND:
1279  case LookupIterator::TRANSITION:
1280  UNREACHABLE();
1281  case LookupIterator::JSPROXY:
1282  return true;
1283  case LookupIterator::INTERCEPTOR: {
1284  Handle<JSObject> holder = it->GetHolder<JSObject>();
1285  InterceptorInfo* info = holder->GetNamedInterceptor();
1286  if (it->HolderIsReceiverOrHiddenPrototype()) {
1287  return !info->non_masking() && receiver.is_identical_to(holder) &&
1288  !info->setter()->IsUndefined(isolate());
1289  } else if (!info->getter()->IsUndefined(isolate()) ||
1290  !info->query()->IsUndefined(isolate())) {
1291  return false;
1292  }
1293  break;
1294  }
1295  case LookupIterator::ACCESS_CHECK:
1296  if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1297  break;
1298  case LookupIterator::ACCESSOR:
1299  return !it->IsReadOnly();
1300  case LookupIterator::INTEGER_INDEXED_EXOTIC:
1301  return false;
1302  case LookupIterator::DATA: {
1303  if (it->IsReadOnly()) return false;
1304  Handle<JSObject> holder = it->GetHolder<JSObject>();
1305  if (receiver.is_identical_to(holder)) {
1306  it->PrepareForDataProperty(value);
1307  // The previous receiver map might just have been deprecated,
1308  // so reload it.
1309  update_receiver_map(receiver);
1310  return true;
1311  }
1312 
1313  // Receiver != holder.
1314  if (receiver->IsJSGlobalProxy()) {
1315  PrototypeIterator iter(isolate(), receiver);
1316  return it->GetHolder<Object>().is_identical_to(
1317  PrototypeIterator::GetCurrent(iter));
1318  }
1319 
1320  if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1321 
1322  if (it->ExtendingNonExtensible(receiver)) return false;
1323  it->PrepareTransitionToDataProperty(receiver, value, NONE,
1324  store_origin);
1325  return it->IsCacheableTransition();
1326  }
1327  }
1328  }
1329  }
1330 
1331  receiver = it->GetStoreTarget<JSObject>();
1332  if (it->ExtendingNonExtensible(receiver)) return false;
1333  it->PrepareTransitionToDataProperty(receiver, value, NONE, store_origin);
1334  return it->IsCacheableTransition();
1335 }
1336 
1337 MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
1338  Handle<Object> value) {
1339  DCHECK(name->IsString());
1340 
1341  // Look up in script context table.
1342  Handle<String> str_name = Handle<String>::cast(name);
1343  Handle<JSGlobalObject> global = isolate()->global_object();
1344  Handle<ScriptContextTable> script_contexts(
1345  global->native_context()->script_context_table(), isolate());
1346 
1347  ScriptContextTable::LookupResult lookup_result;
1348  if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
1349  &lookup_result)) {
1350  Handle<Context> script_context = ScriptContextTable::GetContext(
1351  isolate(), script_contexts, lookup_result.context_index);
1352  if (lookup_result.mode == VariableMode::kConst) {
1353  return TypeError(MessageTemplate::kConstAssign, global, name);
1354  }
1355 
1356  Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
1357  isolate());
1358 
1359  if (previous_value->IsTheHole(isolate())) {
1360  // Do not install stubs and stay pre-monomorphic for
1361  // uninitialized accesses.
1362  return ReferenceError(name);
1363  }
1364 
1365  if (FLAG_use_ic) {
1366  if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
1367  lookup_result.slot_index)) {
1368  TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
1369  } else {
1370  // Given combination of indices can't be encoded, so use slow stub.
1371  TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
1372  PatchCache(name, slow_stub());
1373  }
1374  TraceIC("StoreGlobalIC", name);
1375  }
1376 
1377  script_context->set(lookup_result.slot_index, *value);
1378  return value;
1379  }
1380 
1381  return StoreIC::Store(global, name, value);
1382 }
1383 
1384 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1385  Handle<Object> value,
1386  StoreOrigin store_origin) {
1387  // TODO(verwaest): Let SetProperty do the migration, since storing a property
1388  // might deprecate the current map again, if value does not fit.
1389  if (MigrateDeprecated(object)) {
1390  Handle<Object> result;
1391  ASSIGN_RETURN_ON_EXCEPTION(
1392  isolate(), result,
1393  Object::SetProperty(isolate(), object, name, value, language_mode()),
1394  Object);
1395  return result;
1396  }
1397 
1398  // If the object is undefined or null it's illegal to try to set any
1399  // properties on it; throw a TypeError in that case.
1400  if (object->IsNullOrUndefined(isolate())) {
1401  if (FLAG_use_ic && state() != PREMONOMORPHIC) {
1402  // Ensure the IC state progresses.
1403  TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1404  update_receiver_map(object);
1405  PatchCache(name, slow_stub());
1406  TraceIC("StoreIC", name);
1407  }
1408  return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1409  }
1410 
1411  if (state() != UNINITIALIZED) {
1412  JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1413  }
1414  LookupIterator it(isolate(), object, name);
1415  bool use_ic = FLAG_use_ic;
1416 
1417  if (name->IsPrivate()) {
1418  if (name->IsPrivateName() && !it.IsFound()) {
1419  return TypeError(MessageTemplate::kInvalidPrivateFieldAccess, object,
1420  name);
1421  }
1422 
1423  // IC handling of private fields/symbols stores on JSProxy is not
1424  // supported.
1425  if (object->IsJSProxy()) {
1426  use_ic = false;
1427  }
1428  }
1429  if (use_ic) UpdateCaches(&it, value, store_origin);
1430 
1431  MAYBE_RETURN_NULL(
1432  Object::SetProperty(&it, value, language_mode(), store_origin));
1433  return value;
1434 }
1435 
1436 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1437  StoreOrigin store_origin) {
1438  if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
1439  // This is the first time we execute this inline cache. Transition
1440  // to premonomorphic state to delay setting the monomorphic state.
1441  TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1442  ConfigureVectorState(receiver_map());
1443  TraceIC("StoreIC", lookup->name());
1444  return;
1445  }
1446 
1447  MaybeObjectHandle handler;
1448  if (LookupForWrite(lookup, value, store_origin)) {
1449  if (IsStoreGlobalIC()) {
1450  if (lookup->state() == LookupIterator::DATA &&
1451  lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
1452  DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
1453  // Now update the cell in the feedback vector.
1454  nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1455  TraceIC("StoreGlobalIC", lookup->name());
1456  return;
1457  }
1458  }
1459  handler = ComputeHandler(lookup);
1460  } else {
1461  set_slow_stub_reason("LookupForWrite said 'false'");
1462  // TODO(marja): change slow_stub to return MaybeObjectHandle.
1463  handler = MaybeObjectHandle(slow_stub());
1464  }
1465 
1466  PatchCache(lookup->name(), handler);
1467  TraceIC("StoreIC", lookup->name());
1468 }
1469 
1470 MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
1471  switch (lookup->state()) {
1472  case LookupIterator::TRANSITION: {
1473  Handle<JSObject> store_target = lookup->GetStoreTarget<JSObject>();
1474  if (store_target->IsJSGlobalObject()) {
1475  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1476 
1477  if (receiver_map()->IsJSGlobalObject()) {
1478  DCHECK(IsStoreGlobalIC());
1479 #ifdef DEBUG
1480  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1481  DCHECK_EQ(*lookup->GetReceiver(), *holder);
1482  DCHECK_EQ(*store_target, *holder);
1483 #endif
1484  return StoreHandler::StoreGlobal(lookup->transition_cell());
1485  }
1486 
1487  Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
1488  Handle<Object> handler = StoreHandler::StoreThroughPrototype(
1489  isolate(), receiver_map(), store_target, smi_handler,
1490  MaybeObjectHandle::Weak(lookup->transition_cell()));
1491  return MaybeObjectHandle(handler);
1492  }
1493  // Dictionary-to-fast transitions are not expected and not supported.
1494  DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
1495  !receiver_map()->is_dictionary_map());
1496 
1497  DCHECK(lookup->IsCacheableTransition());
1498 
1499  return StoreHandler::StoreTransition(isolate(), lookup->transition_map());
1500  }
1501 
1502  case LookupIterator::INTERCEPTOR: {
1503  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1504  USE(holder);
1505 
1506  DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1507  // TODO(jgruber): Update counter name.
1508  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1509  return MaybeObjectHandle(BUILTIN_CODE(isolate(), StoreInterceptorIC));
1510  }
1511 
1512  case LookupIterator::ACCESSOR: {
1513  // This is currently guaranteed by checks in StoreIC::Store.
1514  Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1515  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1516  DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1517 
1518  if (!holder->HasFastProperties()) {
1519  set_slow_stub_reason("accessor on slow map");
1520  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1521  return MaybeObjectHandle(slow_stub());
1522  }
1523  Handle<Object> accessors = lookup->GetAccessors();
1524  if (accessors->IsAccessorInfo()) {
1525  Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1526  if (v8::ToCData<Address>(info->setter()) == kNullAddress) {
1527  set_slow_stub_reason("setter == kNullAddress");
1528  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1529  return MaybeObjectHandle(slow_stub());
1530  }
1531  if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1532  !lookup->HolderIsReceiverOrHiddenPrototype()) {
1533  set_slow_stub_reason("special data property in prototype chain");
1534  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1535  return MaybeObjectHandle(slow_stub());
1536  }
1537  if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) {
1538  set_slow_stub_reason("incompatible receiver type");
1539  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1540  return MaybeObjectHandle(slow_stub());
1541  }
1542 
1543  Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty(
1544  isolate(), lookup->GetAccessorIndex());
1545  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH);
1546  if (receiver.is_identical_to(holder)) {
1547  return MaybeObjectHandle(smi_handler);
1548  }
1549  TRACE_HANDLER_STATS(isolate(),
1550  StoreIC_StoreNativeDataPropertyOnPrototypeDH);
1551  return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1552  isolate(), receiver_map(), holder, smi_handler));
1553 
1554  } else if (accessors->IsAccessorPair()) {
1555  Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1556  isolate());
1557  if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
1558  set_slow_stub_reason("setter not a function");
1559  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1560  return MaybeObjectHandle(slow_stub());
1561  }
1562 
1563  if (setter->IsFunctionTemplateInfo() &&
1564  FunctionTemplateInfo::cast(*setter)->BreakAtEntry()) {
1565  // Do not install an IC if the api function has a breakpoint.
1566  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1567  return MaybeObjectHandle(slow_stub());
1568  }
1569 
1570  CallOptimization call_optimization(isolate(), setter);
1571  if (call_optimization.is_simple_api_call()) {
1572  if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1573  CallOptimization::HolderLookup holder_lookup;
1574  call_optimization.LookupHolderOfExpectedType(receiver_map(),
1575  &holder_lookup);
1576 
1577  Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
1578  isolate(),
1579  holder_lookup == CallOptimization::kHolderIsReceiver);
1580 
1581  Handle<Context> context(
1582  call_optimization.GetAccessorContext(holder->map()), isolate());
1583  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
1584  return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1585  isolate(), receiver_map(), holder, smi_handler,
1586  MaybeObjectHandle::Weak(call_optimization.api_call_info()),
1587  MaybeObjectHandle::Weak(context)));
1588  }
1589  set_slow_stub_reason("incompatible receiver");
1590  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1591  return MaybeObjectHandle(slow_stub());
1592  } else if (setter->IsFunctionTemplateInfo()) {
1593  set_slow_stub_reason("setter non-simple template");
1594  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1595  return MaybeObjectHandle(slow_stub());
1596  }
1597 
1598  Handle<Smi> smi_handler =
1599  StoreHandler::StoreAccessor(isolate(), lookup->GetAccessorIndex());
1600 
1601  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH);
1602  if (receiver.is_identical_to(holder)) {
1603  return MaybeObjectHandle(smi_handler);
1604  }
1605  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
1606 
1607  return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1608  isolate(), receiver_map(), holder, smi_handler));
1609  }
1610  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1611  return MaybeObjectHandle(slow_stub());
1612  }
1613 
1614  case LookupIterator::DATA: {
1615  // This is currently guaranteed by checks in StoreIC::Store.
1616  Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1617  USE(receiver);
1618  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1619  DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1620 
1621  DCHECK_EQ(kData, lookup->property_details().kind());
1622  if (lookup->is_dictionary_holder()) {
1623  if (holder->IsJSGlobalObject()) {
1624  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
1625  return MaybeObjectHandle(
1626  StoreHandler::StoreGlobal(lookup->GetPropertyCell()));
1627  }
1628  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
1629  DCHECK(holder.is_identical_to(receiver));
1630  return MaybeObjectHandle(StoreHandler::StoreNormal(isolate()));
1631  }
1632 
1633  // -------------- Fields --------------
1634  if (lookup->property_details().location() == kField) {
1635  TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
1636  int descriptor = lookup->GetFieldDescriptorIndex();
1637  FieldIndex index = lookup->GetFieldIndex();
1638  PropertyConstness constness = lookup->constness();
1639  if (constness == PropertyConstness::kConst &&
1640  IsStoreOwnICKind(nexus()->kind())) {
1641  // StoreOwnICs are used for initializing object literals therefore
1642  // we must store the value unconditionally even to
1643  // VariableMode::kConst fields.
1644  constness = PropertyConstness::kMutable;
1645  }
1646  return MaybeObjectHandle(StoreHandler::StoreField(
1647  isolate(), descriptor, index, constness, lookup->representation()));
1648  }
1649 
1650  // -------------- Constant properties --------------
1651  DCHECK_EQ(kDescriptor, lookup->property_details().location());
1652  set_slow_stub_reason("constant property");
1653  TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1654  return MaybeObjectHandle(slow_stub());
1655  }
1656  case LookupIterator::JSPROXY: {
1657  Handle<JSReceiver> receiver =
1658  Handle<JSReceiver>::cast(lookup->GetReceiver());
1659  Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
1660  return MaybeObjectHandle(StoreHandler::StoreProxy(
1661  isolate(), receiver_map(), holder, receiver));
1662  }
1663 
1664  case LookupIterator::INTEGER_INDEXED_EXOTIC:
1665  case LookupIterator::ACCESS_CHECK:
1666  case LookupIterator::NOT_FOUND:
1667  UNREACHABLE();
1668  }
1669  return MaybeObjectHandle();
1670 }
1671 
1672 void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
1673  KeyedAccessStoreMode store_mode,
1674  bool receiver_was_cow) {
1675  MapHandles target_receiver_maps;
1676  TargetMaps(&target_receiver_maps);
1677  if (target_receiver_maps.empty()) {
1678  Handle<Map> monomorphic_map =
1679  ComputeTransitionedMap(receiver_map, store_mode);
1680  store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1681  Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
1682  return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
1683  }
1684 
1685  for (Handle<Map> map : target_receiver_maps) {
1686  if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) {
1687  DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1688  set_slow_stub_reason("JSValue");
1689  return;
1690  }
1691  }
1692 
1693  // There are several special cases where an IC that is MONOMORPHIC can still
1694  // transition to a different GetNonTransitioningStoreMode IC that handles a
1695  // superset of the original IC. Handle those here if the receiver map hasn't
1696  // changed or it has transitioned to a more general kind.
1697  KeyedAccessStoreMode old_store_mode;
1698  old_store_mode = GetKeyedAccessStoreMode();
1699  Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1700  if (state() == MONOMORPHIC) {
1701  Handle<Map> transitioned_receiver_map = receiver_map;
1702  if (IsTransitionStoreMode(store_mode)) {
1703  transitioned_receiver_map =
1704  ComputeTransitionedMap(receiver_map, store_mode);
1705  }
1706  if ((receiver_map.is_identical_to(previous_receiver_map) &&
1707  IsTransitionStoreMode(store_mode)) ||
1708  IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1709  *transitioned_receiver_map)) {
1710  // If the "old" and "new" maps are in the same elements map family, or
1711  // if they at least come from the same origin for a transitioning store,
1712  // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1713  store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1714  Handle<Object> handler =
1715  StoreElementHandler(transitioned_receiver_map, store_mode);
1716  ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
1717  return;
1718  }
1719  if (receiver_map.is_identical_to(previous_receiver_map) &&
1720  old_store_mode == STANDARD_STORE &&
1721  (store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1722  store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1723  store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1724  // A "normal" IC that handles stores can switch to a version that can
1725  // grow at the end of the array, handle OOB accesses or copy COW arrays
1726  // and still stay MONOMORPHIC.
1727  Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
1728  return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1729  }
1730  }
1731 
1732  DCHECK(state() != GENERIC);
1733 
1734  bool map_added =
1735  AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1736 
1737  if (IsTransitionStoreMode(store_mode)) {
1738  Handle<Map> transitioned_receiver_map =
1739  ComputeTransitionedMap(receiver_map, store_mode);
1740  map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1741  transitioned_receiver_map);
1742  }
1743 
1744  if (!map_added) {
1745  // If the miss wasn't due to an unseen map, a polymorphic stub
1746  // won't help, use the megamorphic stub which can handle everything.
1747  set_slow_stub_reason("same map added twice");
1748  return;
1749  }
1750 
1751  // If the maximum number of receiver maps has been exceeded, use the
1752  // megamorphic version of the IC.
1753  if (target_receiver_maps.size() > kMaxKeyedPolymorphism) return;
1754 
1755  // Make sure all polymorphic handlers have the same store mode, otherwise the
1756  // megamorphic stub must be used.
1757  store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1758  if (old_store_mode != STANDARD_STORE) {
1759  if (store_mode == STANDARD_STORE) {
1760  store_mode = old_store_mode;
1761  } else if (store_mode != old_store_mode) {
1762  set_slow_stub_reason("store mode mismatch");
1763  return;
1764  }
1765  }
1766 
1767  // If the store mode isn't the standard mode, make sure that all polymorphic
1768  // receivers are either external arrays, or all "normal" arrays. Otherwise,
1769  // use the megamorphic stub.
1770  if (store_mode != STANDARD_STORE) {
1771  size_t external_arrays = 0;
1772  for (Handle<Map> map : target_receiver_maps) {
1773  if (map->has_fixed_typed_array_elements()) {
1774  DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1775  external_arrays++;
1776  }
1777  }
1778  if (external_arrays != 0 &&
1779  external_arrays != target_receiver_maps.size()) {
1780  DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1781  set_slow_stub_reason(
1782  "unsupported combination of external and normal arrays");
1783  return;
1784  }
1785  }
1786 
1787  MaybeObjectHandles handlers;
1788  handlers.reserve(target_receiver_maps.size());
1789  StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
1790  if (target_receiver_maps.size() == 0) {
1791  // Transition to PREMONOMORPHIC state here and remember a weak-reference
1792  // to the {receiver_map} in case TurboFan sees this function before the
1793  // IC can transition further.
1794  ConfigureVectorState(receiver_map);
1795  } else if (target_receiver_maps.size() == 1) {
1796  ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1797  } else {
1798  ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1799  }
1800 }
1801 
1802 
1803 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1804  Handle<Map> map, KeyedAccessStoreMode store_mode) {
1805  switch (store_mode) {
1806  case STORE_TRANSITION_TO_OBJECT:
1807  case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1808  ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1809  ? HOLEY_ELEMENTS
1810  : PACKED_ELEMENTS;
1811  return Map::TransitionElementsTo(isolate(), map, kind);
1812  }
1813  case STORE_TRANSITION_TO_DOUBLE:
1814  case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1815  ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1816  ? HOLEY_DOUBLE_ELEMENTS
1817  : PACKED_DOUBLE_ELEMENTS;
1818  return Map::TransitionElementsTo(isolate(), map, kind);
1819  }
1820  case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1821  DCHECK(map->has_fixed_typed_array_elements());
1822  V8_FALLTHROUGH;
1823  case STORE_NO_TRANSITION_HANDLE_COW:
1824  case STANDARD_STORE:
1825  case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
1826  return map;
1827  }
1828  UNREACHABLE();
1829 }
1830 
1831 Handle<Object> KeyedStoreIC::StoreElementHandler(
1832  Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1833  DCHECK(store_mode == STANDARD_STORE ||
1834  store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1835  store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1836  store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1837  DCHECK_IMPLIES(
1838  receiver_map->DictionaryElementsInPrototypeChainOnly(isolate()),
1839  IsStoreInArrayLiteralICKind(kind()));
1840 
1841  if (receiver_map->IsJSProxyMap()) {
1842  return StoreHandler::StoreProxy(isolate());
1843  }
1844 
1845  // TODO(ishell): move to StoreHandler::StoreElement().
1846  Handle<Code> code;
1847  if (receiver_map->has_sloppy_arguments_elements()) {
1848  // TODO(jgruber): Update counter name.
1849  TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
1850  code =
1851  CodeFactory::KeyedStoreIC_SloppyArguments(isolate(), store_mode).code();
1852  } else if (receiver_map->has_fast_elements() ||
1853  receiver_map->has_fixed_typed_array_elements()) {
1854  TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
1855  code = CodeFactory::StoreFastElementIC(isolate(), store_mode).code();
1856  if (receiver_map->has_fixed_typed_array_elements()) return code;
1857  } else if (IsStoreInArrayLiteralICKind(kind())) {
1858  // TODO(jgruber): Update counter name.
1859  TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
1860  code =
1861  CodeFactory::StoreInArrayLiteralIC_Slow(isolate(), store_mode).code();
1862  } else {
1863  // TODO(jgruber): Update counter name.
1864  TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
1865  DCHECK_EQ(DICTIONARY_ELEMENTS, receiver_map->elements_kind());
1866  code = CodeFactory::KeyedStoreIC_Slow(isolate(), store_mode).code();
1867  }
1868 
1869  if (IsStoreInArrayLiteralICKind(kind())) return code;
1870 
1871  Handle<Object> validity_cell =
1872  Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1873  if (validity_cell->IsSmi()) {
1874  // There's no prototype validity cell to check, so we can just use the stub.
1875  return code;
1876  }
1877  Handle<StoreHandler> handler = isolate()->factory()->NewStoreHandler(0);
1878  handler->set_validity_cell(*validity_cell);
1879  handler->set_smi_handler(*code);
1880  return handler;
1881 }
1882 
1883 void KeyedStoreIC::StoreElementPolymorphicHandlers(
1884  MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1885  KeyedAccessStoreMode store_mode) {
1886  DCHECK(store_mode == STANDARD_STORE ||
1887  store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1888  store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1889  store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1890 
1891  // Filter out deprecated maps to ensure their instances get migrated.
1892  receiver_maps->erase(
1893  std::remove_if(
1894  receiver_maps->begin(), receiver_maps->end(),
1895  [](const Handle<Map>& map) { return map->is_deprecated(); }),
1896  receiver_maps->end());
1897 
1898  for (Handle<Map> receiver_map : *receiver_maps) {
1899  Handle<Object> handler;
1900  Handle<Map> transition;
1901 
1902  if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
1903  receiver_map->DictionaryElementsInPrototypeChainOnly(isolate())) {
1904  // TODO(mvstanton): Consider embedding store_mode in the state of the slow
1905  // keyed store ic for uniformity.
1906  TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
1907  handler = slow_stub();
1908 
1909  } else {
1910  {
1911  Map tmap = receiver_map->FindElementsKindTransitionedMap(
1912  isolate(), *receiver_maps);
1913  if (!tmap.is_null()) {
1914  if (receiver_map->is_stable()) {
1915  receiver_map->NotifyLeafMapLayoutChange(isolate());
1916  }
1917  transition = handle(tmap, isolate());
1918  }
1919  }
1920 
1921  // TODO(mvstanton): The code below is doing pessimistic elements
1922  // transitions. I would like to stop doing that and rely on Allocation
1923  // Site Tracking to do a better job of ensuring the data types are what
1924  // they need to be. Not all the elements are in place yet, pessimistic
1925  // elements transitions are still important for performance.
1926  if (!transition.is_null()) {
1927  TRACE_HANDLER_STATS(isolate(),
1928  KeyedStoreIC_ElementsTransitionAndStoreStub);
1929  handler = StoreHandler::StoreElementTransition(isolate(), receiver_map,
1930  transition, store_mode);
1931  } else {
1932  handler = StoreElementHandler(receiver_map, store_mode);
1933  }
1934  }
1935  DCHECK(!handler.is_null());
1936  handlers->push_back(MaybeObjectHandle(handler));
1937  }
1938 }
1939 
1940 
1941 static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
1942  uint32_t index, Handle<Object> value) {
1943  bool oob_access = IsOutOfBoundsAccess(receiver, index);
1944  // Don't consider this a growing store if the store would send the receiver to
1945  // dictionary mode.
1946  bool allow_growth = receiver->IsJSArray() && oob_access &&
1947  !receiver->WouldConvertToSlowElements(index);
1948  if (allow_growth) {
1949  // Handle growing array in stub if necessary.
1950  if (receiver->HasSmiElements()) {
1951  if (value->IsHeapNumber()) {
1952  return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
1953  }
1954  if (value->IsHeapObject()) {
1955  return STORE_AND_GROW_TRANSITION_TO_OBJECT;
1956  }
1957  } else if (receiver->HasDoubleElements()) {
1958  if (!value->IsSmi() && !value->IsHeapNumber()) {
1959  return STORE_AND_GROW_TRANSITION_TO_OBJECT;
1960  }
1961  }
1962  return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1963  } else {
1964  // Handle only in-bounds elements accesses.
1965  if (receiver->HasSmiElements()) {
1966  if (value->IsHeapNumber()) {
1967  return STORE_TRANSITION_TO_DOUBLE;
1968  } else if (value->IsHeapObject()) {
1969  return STORE_TRANSITION_TO_OBJECT;
1970  }
1971  } else if (receiver->HasDoubleElements()) {
1972  if (!value->IsSmi() && !value->IsHeapNumber()) {
1973  return STORE_TRANSITION_TO_OBJECT;
1974  }
1975  }
1976  if (!FLAG_trace_external_array_abuse &&
1977  receiver->map()->has_fixed_typed_array_elements() && oob_access) {
1978  return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1979  }
1980  return receiver->elements()->IsCowArray() ? STORE_NO_TRANSITION_HANDLE_COW
1981  : STANDARD_STORE;
1982  }
1983 }
1984 
1985 
1986 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
1987  Handle<Object> key,
1988  Handle<Object> value) {
1989  // TODO(verwaest): Let SetProperty do the migration, since storing a property
1990  // might deprecate the current map again, if value does not fit.
1991  if (MigrateDeprecated(object)) {
1992  Handle<Object> result;
1993  ASSIGN_RETURN_ON_EXCEPTION(
1994  isolate(), result,
1995  Runtime::SetObjectProperty(isolate(), object, key, value,
1996  language_mode(), StoreOrigin::kMaybeKeyed),
1997  Object);
1998  return result;
1999  }
2000 
2001  // Check for non-string values that can be converted into an
2002  // internalized string directly or is representable as a smi.
2003  key = TryConvertKey(key, isolate());
2004 
2005  Handle<Object> store_handle;
2006 
2007  uint32_t index;
2008  if ((key->IsInternalizedString() &&
2009  !String::cast(*key)->AsArrayIndex(&index)) ||
2010  key->IsSymbol()) {
2011  ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2012  StoreIC::Store(object, Handle<Name>::cast(key),
2013  value, StoreOrigin::kMaybeKeyed),
2014  Object);
2015  if (vector_needs_update()) {
2016  if (ConfigureVectorState(MEGAMORPHIC, key)) {
2017  set_slow_stub_reason("unhandled internalized string key");
2018  TraceIC("StoreIC", key);
2019  }
2020  }
2021  return store_handle;
2022  }
2023 
2024  JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
2025 
2026  bool use_ic = FLAG_use_ic && !object->IsStringWrapper() &&
2027  !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy();
2028  if (use_ic && !object->IsSmi()) {
2029  // Don't use ICs for maps of the objects in Array's prototype chain. We
2030  // expect to be able to trap element sets to objects with those maps in
2031  // the runtime to enable optimization of element hole access.
2032  Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2033  if (heap_object->map()->IsMapInArrayPrototypeChain(isolate())) {
2034  set_slow_stub_reason("map in array prototype");
2035  use_ic = false;
2036  }
2037  }
2038 
2039  Handle<Map> old_receiver_map;
2040  bool is_arguments = false;
2041  bool key_is_valid_index = false;
2042  KeyedAccessStoreMode store_mode = STANDARD_STORE;
2043  if (use_ic && object->IsJSReceiver()) {
2044  Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
2045  old_receiver_map = handle(receiver->map(), isolate());
2046  is_arguments = receiver->IsJSArgumentsObject();
2047  bool is_proxy = receiver->IsJSProxy();
2048  // For JSTypedArray {object}s we can handle negative indices as OOB
2049  // accesses, since integer indexed properties are never looked up
2050  // on the prototype chain. For this we simply map the negative {key}s
2051  // to the [2**31,2**32-1] range, which is safe since JSTypedArray::length
2052  // is always an unsigned Smi.
2053  key_is_valid_index =
2054  key->IsSmi() && (Smi::ToInt(*key) >= 0 || object->IsJSTypedArray());
2055  if (!is_arguments && !is_proxy) {
2056  if (key_is_valid_index) {
2057  uint32_t index = static_cast<uint32_t>(Smi::ToInt(*key));
2058  Handle<JSObject> receiver_object = Handle<JSObject>::cast(object);
2059  store_mode = GetStoreMode(receiver_object, index, value);
2060  }
2061  }
2062  }
2063 
2064  DCHECK(store_handle.is_null());
2065  bool receiver_was_cow =
2066  object->IsJSArray() &&
2067  Handle<JSArray>::cast(object)->elements()->IsCowArray();
2068  ASSIGN_RETURN_ON_EXCEPTION(
2069  isolate(), store_handle,
2070  Runtime::SetObjectProperty(isolate(), object, key, value, language_mode(),
2071  StoreOrigin::kMaybeKeyed),
2072  Object);
2073 
2074  if (use_ic) {
2075  if (!old_receiver_map.is_null()) {
2076  if (is_arguments) {
2077  set_slow_stub_reason("arguments receiver");
2078  } else if (key_is_valid_index) {
2079  if (old_receiver_map->is_abandoned_prototype_map()) {
2080  set_slow_stub_reason("receiver with prototype map");
2081  } else if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly(
2082  isolate())) {
2083  // We should go generic if receiver isn't a dictionary, but our
2084  // prototype chain does have dictionary elements. This ensures that
2085  // other non-dictionary receivers in the polymorphic case benefit
2086  // from fast path keyed stores.
2087  UpdateStoreElement(old_receiver_map, store_mode, receiver_was_cow);
2088  } else {
2089  set_slow_stub_reason("dictionary or proxy prototype");
2090  }
2091  } else {
2092  set_slow_stub_reason("non-smi-like key");
2093  }
2094  } else {
2095  set_slow_stub_reason("non-JSObject receiver");
2096  }
2097  }
2098 
2099  if (vector_needs_update()) {
2100  ConfigureVectorState(MEGAMORPHIC, key);
2101  }
2102  TraceIC("StoreIC", key);
2103 
2104  return store_handle;
2105 }
2106 
2107 namespace {
2108 void StoreOwnElement(Isolate* isolate, Handle<JSArray> array,
2109  Handle<Object> index, Handle<Object> value) {
2110  DCHECK(index->IsNumber());
2111  bool success = false;
2112  LookupIterator it = LookupIterator::PropertyOrElement(
2113  isolate, array, index, &success, LookupIterator::OWN);
2114  DCHECK(success);
2115 
2116  CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE,
2117  kThrowOnError)
2118  .FromJust());
2119 }
2120 } // namespace
2121 
2122 void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
2123  Handle<Object> value) {
2124  DCHECK(!array->map()->IsMapInArrayPrototypeChain(isolate()));
2125  DCHECK(index->IsNumber());
2126 
2127  if (!FLAG_use_ic || MigrateDeprecated(array)) {
2128  StoreOwnElement(isolate(), array, index, value);
2129  TraceIC("StoreInArrayLiteralIC", index);
2130  return;
2131  }
2132 
2133  // TODO(neis): Convert HeapNumber to Smi if possible?
2134 
2135  KeyedAccessStoreMode store_mode = STANDARD_STORE;
2136  if (index->IsSmi()) {
2137  DCHECK_GE(Smi::ToInt(*index), 0);
2138  uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
2139  store_mode = GetStoreMode(array, index32, value);
2140  }
2141 
2142  Handle<Map> old_array_map(array->map(), isolate());
2143  bool array_was_cow = array->elements()->IsCowArray();
2144  StoreOwnElement(isolate(), array, index, value);
2145 
2146  if (index->IsSmi()) {
2147  DCHECK(!old_array_map->is_abandoned_prototype_map());
2148  UpdateStoreElement(old_array_map, store_mode, array_was_cow);
2149  } else {
2150  set_slow_stub_reason("index out of Smi range");
2151  }
2152 
2153  if (vector_needs_update()) {
2154  ConfigureVectorState(MEGAMORPHIC, index);
2155  }
2156  TraceIC("StoreInArrayLiteralIC", index);
2157 }
2158 
2159 // ----------------------------------------------------------------------------
2160 // Static IC stub generators.
2161 //
2162 
2163 RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2164  HandleScope scope(isolate);
2165  DCHECK_EQ(4, args.length());
2166  // Runtime functions don't follow the IC's calling convention.
2167  Handle<Object> receiver = args.at(0);
2168  Handle<Name> key = args.at<Name>(1);
2169  Handle<Smi> slot = args.at<Smi>(2);
2170  Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2171  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2172  // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2173  // LoadIC miss handler if the handler misses. Since the vector Nexus is
2174  // set up outside the IC, handle that here.
2175  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2176  if (IsLoadICKind(kind)) {
2177  LoadIC ic(isolate, vector, vector_slot);
2178  ic.UpdateState(receiver, key);
2179  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2180 
2181  } else if (IsLoadGlobalICKind(kind)) {
2182  DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2183  receiver = isolate->global_object();
2184  LoadGlobalIC ic(isolate, vector, vector_slot);
2185  ic.UpdateState(receiver, key);
2186  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2187 
2188  } else {
2189  DCHECK(IsKeyedLoadICKind(kind));
2190  KeyedLoadIC ic(isolate, vector, vector_slot);
2191  ic.UpdateState(receiver, key);
2192  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2193  }
2194 }
2195 
2196 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2197  HandleScope scope(isolate);
2198  DCHECK_EQ(3, args.length());
2199  // Runtime functions don't follow the IC's calling convention.
2200  Handle<JSGlobalObject> global = isolate->global_object();
2201  Handle<String> name = args.at<String>(0);
2202  Handle<Smi> slot = args.at<Smi>(1);
2203  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2204  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2205 
2206  LoadGlobalIC ic(isolate, vector, vector_slot);
2207  ic.UpdateState(global, name);
2208 
2209  Handle<Object> result;
2210  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2211  return *result;
2212 }
2213 
2214 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2215  HandleScope scope(isolate);
2216  DCHECK_EQ(3, args.length());
2217  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2218 
2219  Handle<Context> native_context = isolate->native_context();
2220  Handle<ScriptContextTable> script_contexts(
2221  native_context->script_context_table(), isolate);
2222 
2223  ScriptContextTable::LookupResult lookup_result;
2224  if (ScriptContextTable::Lookup(isolate, script_contexts, name,
2225  &lookup_result)) {
2226  Handle<Context> script_context = ScriptContextTable::GetContext(
2227  isolate, script_contexts, lookup_result.context_index);
2228  Handle<Object> result(script_context->get(lookup_result.slot_index),
2229  isolate);
2230  if (*result == ReadOnlyRoots(isolate).the_hole_value()) {
2231  THROW_NEW_ERROR_RETURN_FAILURE(
2232  isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2233  }
2234  return *result;
2235  }
2236 
2237  Handle<JSGlobalObject> global(native_context->global_object(), isolate);
2238  Handle<Object> result;
2239  bool is_found = false;
2240  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2241  isolate, result,
2242  Runtime::GetObjectProperty(isolate, global, name, &is_found));
2243  if (!is_found) {
2244  Handle<Smi> slot = args.at<Smi>(1);
2245  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2246  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2247  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2248  // It is actually a LoadGlobalICs here but the predicate handles this case
2249  // properly.
2250  if (LoadIC::ShouldThrowReferenceError(kind)) {
2251  THROW_NEW_ERROR_RETURN_FAILURE(
2252  isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2253  }
2254  }
2255  return *result;
2256 }
2257 
2258 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2259  HandleScope scope(isolate);
2260  DCHECK_EQ(4, args.length());
2261  // Runtime functions don't follow the IC's calling convention.
2262  Handle<Object> receiver = args.at(0);
2263  Handle<Object> key = args.at(1);
2264  Handle<Smi> slot = args.at<Smi>(2);
2265  Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2266  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2267  KeyedLoadIC ic(isolate, vector, vector_slot);
2268  ic.UpdateState(receiver, key);
2269  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2270 }
2271 
2272 RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2273  HandleScope scope(isolate);
2274  DCHECK_EQ(5, args.length());
2275  // Runtime functions don't follow the IC's calling convention.
2276  Handle<Object> value = args.at(0);
2277  Handle<Smi> slot = args.at<Smi>(1);
2278  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2279  Handle<Object> receiver = args.at(3);
2280  Handle<Name> key = args.at<Name>(4);
2281  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2282  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2283  if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
2284  StoreIC ic(isolate, vector, vector_slot);
2285  ic.UpdateState(receiver, key);
2286  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2287  } else if (IsStoreGlobalICKind(kind)) {
2288  DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2289  receiver = isolate->global_object();
2290  StoreGlobalIC ic(isolate, vector, vector_slot);
2291  ic.UpdateState(receiver, key);
2292  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2293  } else {
2294  DCHECK(IsKeyedStoreICKind(kind));
2295  KeyedStoreIC ic(isolate, vector, vector_slot);
2296  ic.UpdateState(receiver, key);
2297  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2298  }
2299 }
2300 
2301 RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
2302  HandleScope scope(isolate);
2303  DCHECK_EQ(4, args.length());
2304  // Runtime functions don't follow the IC's calling convention.
2305  Handle<Object> value = args.at(0);
2306  Handle<Smi> slot = args.at<Smi>(1);
2307  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2308  Handle<Name> key = args.at<Name>(3);
2309  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2310  StoreGlobalIC ic(isolate, vector, vector_slot);
2311  Handle<JSGlobalObject> global = isolate->global_object();
2312  ic.UpdateState(global, key);
2313  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2314 }
2315 
2316 RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
2317  HandleScope scope(isolate);
2318  DCHECK_EQ(5, args.length());
2319  // Runtime functions don't follow the IC's calling convention.
2320  Handle<Object> value = args.at(0);
2321  Handle<Smi> slot = args.at<Smi>(1);
2322  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2323  CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
2324 
2325 #ifdef DEBUG
2326  {
2327  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2328  FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2329  DCHECK(IsStoreGlobalICKind(slot_kind));
2330  Handle<Object> receiver = args.at(3);
2331  DCHECK(receiver->IsJSGlobalProxy());
2332  }
2333 #endif
2334 
2335  Handle<JSGlobalObject> global = isolate->global_object();
2336  Handle<Context> native_context = isolate->native_context();
2337  Handle<ScriptContextTable> script_contexts(
2338  native_context->script_context_table(), isolate);
2339 
2340  ScriptContextTable::LookupResult lookup_result;
2341  if (ScriptContextTable::Lookup(isolate, script_contexts, name,
2342  &lookup_result)) {
2343  Handle<Context> script_context = ScriptContextTable::GetContext(
2344  isolate, script_contexts, lookup_result.context_index);
2345  if (lookup_result.mode == VariableMode::kConst) {
2346  THROW_NEW_ERROR_RETURN_FAILURE(
2347  isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
2348  }
2349 
2350  Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
2351  isolate);
2352 
2353  if (previous_value->IsTheHole(isolate)) {
2354  THROW_NEW_ERROR_RETURN_FAILURE(
2355  isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2356  }
2357 
2358  script_context->set(lookup_result.slot_index, *value);
2359  return *value;
2360  }
2361 
2362  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2363  LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2364  RETURN_RESULT_OR_FAILURE(
2365  isolate,
2366  Runtime::SetObjectProperty(isolate, global, name, value, language_mode,
2367  StoreOrigin::kMaybeKeyed));
2368 }
2369 
2370 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2371  HandleScope scope(isolate);
2372  DCHECK_EQ(5, args.length());
2373  // Runtime functions don't follow the IC's calling convention.
2374  Handle<Object> value = args.at(0);
2375  Handle<Smi> slot = args.at<Smi>(1);
2376  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2377  Handle<Object> receiver = args.at(3);
2378  Handle<Object> key = args.at(4);
2379  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2380  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2381 
2382  // The elements store stubs miss into this function, but they are shared by
2383  // different ICs.
2384  if (IsKeyedStoreICKind(kind)) {
2385  KeyedStoreIC ic(isolate, vector, vector_slot);
2386  ic.UpdateState(receiver, key);
2387  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2388  } else {
2389  DCHECK(IsStoreInArrayLiteralICKind(kind));
2390  DCHECK(receiver->IsJSArray());
2391  DCHECK(key->IsNumber());
2392  StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
2393  ic.UpdateState(receiver, key);
2394  ic.Store(Handle<JSArray>::cast(receiver), key, value);
2395  return *value;
2396  }
2397 }
2398 
2399 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2400  HandleScope scope(isolate);
2401  DCHECK_EQ(5, args.length());
2402  // Runtime functions don't follow the IC's calling convention.
2403  Handle<Object> value = args.at(0);
2404  Handle<Smi> slot = args.at<Smi>(1);
2405  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2406  Handle<Object> object = args.at(3);
2407  Handle<Object> key = args.at(4);
2408  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2409  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2410  DCHECK(IsStoreICKind(kind) || IsKeyedStoreICKind(kind));
2411  LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
2412  RETURN_RESULT_OR_FAILURE(
2413  isolate,
2414  Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
2415  StoreOrigin::kMaybeKeyed));
2416 }
2417 
2418 RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
2419  HandleScope scope(isolate);
2420  DCHECK_EQ(3, args.length());
2421  // Runtime functions don't follow the IC's calling convention.
2422  Handle<Object> value = args.at(0);
2423  Handle<Object> array = args.at(1);
2424  Handle<Object> index = args.at(2);
2425  StoreOwnElement(isolate, Handle<JSArray>::cast(array), index, value);
2426  return *value;
2427 }
2428 
2429 RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2430  HandleScope scope(isolate);
2431  DCHECK_EQ(6, args.length());
2432  // Runtime functions don't follow the IC's calling convention.
2433  Handle<Object> object = args.at(0);
2434  Handle<Object> key = args.at(1);
2435  Handle<Object> value = args.at(2);
2436  Handle<Map> map = args.at<Map>(3);
2437  Handle<Smi> slot = args.at<Smi>(4);
2438  Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
2439  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2440  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2441 
2442  if (object->IsJSObject()) {
2443  JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2444  map->elements_kind());
2445  }
2446 
2447  if (IsStoreInArrayLiteralICKind(kind)) {
2448  StoreOwnElement(isolate, Handle<JSArray>::cast(object), key, value);
2449  return *value;
2450  } else {
2451  DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
2452  LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
2453  RETURN_RESULT_OR_FAILURE(
2454  isolate,
2455  Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
2456  StoreOrigin::kMaybeKeyed));
2457  }
2458 }
2459 
2460 static bool CanFastCloneObject(Handle<Map> map) {
2461  DisallowHeapAllocation no_gc;
2462  if (map->IsNullOrUndefinedMap()) return true;
2463  if (!map->IsJSObjectMap() ||
2464  !IsSmiOrObjectElementsKind(map->elements_kind()) ||
2465  !map->OnlyHasSimpleProperties()) {
2466  return false;
2467  }
2468 
2469  DescriptorArray* descriptors = map->instance_descriptors();
2470  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
2471  PropertyDetails details = descriptors->GetDetails(i);
2472  Name key = descriptors->GetKey(i);
2473  if (details.kind() != kData || !details.IsEnumerable() ||
2474  key->IsPrivateName()) {
2475  return false;
2476  }
2477  }
2478 
2479  return true;
2480 }
2481 
2482 static Handle<Map> FastCloneObjectMap(Isolate* isolate,
2483  Handle<HeapObject> source, int flags) {
2484  Handle<Map> source_map(source->map(), isolate);
2485  SLOW_DCHECK(source->IsNullOrUndefined() || CanFastCloneObject(source_map));
2486  Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2487  isolate);
2488  DCHECK(constructor->has_initial_map());
2489  Handle<Map> initial_map(constructor->initial_map(), isolate);
2490  Handle<Map> map = initial_map;
2491 
2492  if (source_map->IsJSObjectMap() && source_map->GetInObjectProperties() !=
2493  initial_map->GetInObjectProperties()) {
2494  int inobject_properties = source_map->GetInObjectProperties();
2495  int instance_size =
2496  JSObject::kHeaderSize + kPointerSize * inobject_properties;
2497  int unused = source_map->UnusedInObjectProperties();
2498  DCHECK(instance_size <= JSObject::kMaxInstanceSize);
2499  map = Map::CopyInitialMap(isolate, map, instance_size, inobject_properties,
2500  unused);
2501  }
2502 
2503  if (flags & ObjectLiteral::kHasNullPrototype) {
2504  if (map.is_identical_to(initial_map)) {
2505  map = Map::Copy(isolate, map, "ObjectWithNullProto");
2506  }
2507  Map::SetPrototype(isolate, map, isolate->factory()->null_value());
2508  }
2509 
2510  if (source->IsNullOrUndefined() || !source_map->NumberOfOwnDescriptors()) {
2511  return map;
2512  }
2513 
2514  if (map.is_identical_to(initial_map)) {
2515  map = Map::Copy(isolate, map, "InitializeClonedDescriptors");
2516  }
2517 
2518  Handle<DescriptorArray> source_descriptors(source_map->instance_descriptors(),
2519  isolate);
2520  int size = source_map->NumberOfOwnDescriptors();
2521  int slack = 0;
2522  Handle<DescriptorArray> descriptors = DescriptorArray::CopyForFastObjectClone(
2523  isolate, source_descriptors, size, slack);
2524  Handle<LayoutDescriptor> layout =
2525  LayoutDescriptor::New(isolate, map, descriptors, size);
2526  map->InitializeDescriptors(*descriptors, *layout);
2527  map->CopyUnusedPropertyFieldsAdjustedForInstanceSize(*source_map);
2528 
2529  // Update bitfields
2530  map->set_may_have_interesting_symbols(
2531  source_map->may_have_interesting_symbols());
2532 
2533  return map;
2534 }
2535 
2536 static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
2537  Handle<HeapObject> source,
2538  int flags) {
2539  Handle<JSObject> new_object;
2540  if (flags & ObjectLiteral::kHasNullPrototype) {
2541  new_object = isolate->factory()->NewJSObjectWithNullProto();
2542  } else {
2543  Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2544  isolate);
2545  new_object = isolate->factory()->NewJSObject(constructor);
2546  }
2547 
2548  if (source->IsNullOrUndefined()) {
2549  return new_object;
2550  }
2551 
2552  MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source,
2553  nullptr, false),
2554  MaybeHandle<JSObject>());
2555  return new_object;
2556 }
2557 
2558 RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) {
2559  HandleScope scope(isolate);
2560  DCHECK_EQ(4, args.length());
2561  Handle<HeapObject> source = args.at<HeapObject>(0);
2562  int flags = args.smi_at(1);
2563 
2564  MigrateDeprecated(source);
2565 
2566  FeedbackSlot slot = FeedbackVector::ToSlot(args.smi_at(2));
2567  Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2568 
2569  FeedbackNexus nexus(vector, slot);
2570  Handle<Map> source_map(source->map(), isolate);
2571 
2572  if (!CanFastCloneObject(source_map) || nexus.IsMegamorphic()) {
2573  // Migrate to slow mode if needed.
2574  nexus.ConfigureMegamorphic();
2575  RETURN_RESULT_OR_FAILURE(isolate,
2576  CloneObjectSlowPath(isolate, source, flags));
2577  }
2578 
2579  Handle<Map> result_map = FastCloneObjectMap(isolate, source, flags);
2580  nexus.ConfigureCloneObject(source_map, result_map);
2581 
2582  return *result_map;
2583 }
2584 
2585 RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
2586  Handle<JSObject> receiver = args.at<JSObject>(0);
2587  Handle<JSObject> holder = args.at<JSObject>(1);
2588  Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2589  Handle<Name> name = args.at<Name>(3);
2590  Handle<Object> value = args.at(4);
2591  CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
2592  HandleScope scope(isolate);
2593 
2594  if (V8_UNLIKELY(FLAG_runtime_stats)) {
2595  RETURN_RESULT_OR_FAILURE(
2596  isolate,
2597  Runtime::SetObjectProperty(isolate, receiver, name, value,
2598  language_mode, StoreOrigin::kMaybeKeyed));
2599  }
2600 
2601  DCHECK(info->IsCompatibleReceiver(*receiver));
2602 
2603  ShouldThrow should_throw =
2604  is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
2605  PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
2606  should_throw);
2607  arguments.CallAccessorSetter(info, name, value);
2608  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2609  return *value;
2610 }
2611 
2612 RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) {
2613  Handle<JSObject> receiver = args.at<JSObject>(0);
2614  Handle<JSObject> holder = args.at<JSObject>(1);
2615  Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2616  Handle<Name> name = args.at<Name>(3);
2617  HandleScope scope(isolate);
2618 
2619  DCHECK(info->IsCompatibleReceiver(*receiver));
2620 
2621  PropertyCallbackArguments custom_args(isolate, info->data(), *receiver,
2622  *holder, kThrowOnError);
2623  Handle<Object> result = custom_args.CallAccessorGetter(info, name);
2624  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2625  if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2626  return *result;
2627 }
2628 
2629 RUNTIME_FUNCTION(Runtime_LoadAccessorProperty) {
2630  HandleScope scope(isolate);
2631  DCHECK_EQ(args.length(), 3);
2632  Handle<JSObject> receiver = args.at<JSObject>(0);
2633  int handler_kind = args.smi_at(1);
2634  Handle<CallHandlerInfo> call_handler_info = args.at<CallHandlerInfo>(2);
2635 
2636  Object* holder = *receiver;
2637  if (handler_kind == LoadHandler::kApiGetterHolderIsPrototype) {
2638  holder = receiver->map()->prototype();
2639  } else {
2640  DCHECK_EQ(handler_kind, LoadHandler::kApiGetter);
2641  }
2642 
2643  // Call the accessor without additional arguments.
2644  FunctionCallbackArguments custom(isolate, call_handler_info->data(),
2645  *receiver, holder, nullptr, nullptr, 0);
2646  Handle<Object> result_handle = custom.Call(*call_handler_info);
2647  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2648  if (result_handle.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2649  return *result_handle;
2650 }
2651 
2656 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
2657  HandleScope scope(isolate);
2658  DCHECK_EQ(5, args.length());
2659  Handle<Name> name = args.at<Name>(0);
2660  Handle<Object> receiver = args.at(1);
2661  Handle<JSObject> holder = args.at<JSObject>(2);
2662 
2663  if (!receiver->IsJSReceiver()) {
2664  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2665  isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2666  }
2667 
2668  Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
2669  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2670  *holder, kDontThrow);
2671  Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
2672 
2673  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2674 
2675  if (!result.is_null()) return *result;
2676 
2677  LookupIterator it(receiver, name, holder);
2678  // Skip any lookup work until we hit the (possibly non-masking) interceptor.
2679  while (it.state() != LookupIterator::INTERCEPTOR ||
2680  !it.GetHolder<JSObject>().is_identical_to(holder)) {
2681  DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
2682  it.Next();
2683  }
2684  // Skip past the interceptor.
2685  it.Next();
2686  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
2687 
2688  if (it.IsFound()) return *result;
2689 
2690  Handle<Smi> slot = args.at<Smi>(3);
2691  Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
2692  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2693  FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2694  // It could actually be any kind of load IC slot here but the predicate
2695  // handles all the cases properly.
2696  if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
2697  return ReadOnlyRoots(isolate).undefined_value();
2698  }
2699 
2700  // Throw a reference error.
2701  THROW_NEW_ERROR_RETURN_FAILURE(
2702  isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
2703 }
2704 
2705 
2706 RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
2707  HandleScope scope(isolate);
2708  DCHECK_EQ(5, args.length());
2709  // Runtime functions don't follow the IC's calling convention.
2710  Handle<Object> value = args.at(0);
2711  Handle<Smi> slot = args.at<Smi>(1);
2712  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2713  Handle<JSObject> receiver = args.at<JSObject>(3);
2714  Handle<Name> name = args.at<Name>(4);
2715  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2716  LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2717 
2718  // TODO(ishell): Cache interceptor_holder in the store handler like we do
2719  // for LoadHandler::kInterceptor case.
2720  Handle<JSObject> interceptor_holder = receiver;
2721  if (receiver->IsJSGlobalProxy()) {
2722  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2723  if (IsStoreGlobalICKind(kind)) {
2724  interceptor_holder = Handle<JSObject>::cast(isolate->global_object());
2725  }
2726  }
2727  DCHECK(interceptor_holder->HasNamedInterceptor());
2728  Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(),
2729  isolate);
2730 
2731  DCHECK(!interceptor->non_masking());
2732  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2733  *receiver, kDontThrow);
2734 
2735  Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
2736  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2737  if (!result.is_null()) return *value;
2738 
2739  LookupIterator it(receiver, name, receiver);
2740  // Skip past any access check on the receiver.
2741  if (it.state() == LookupIterator::ACCESS_CHECK) {
2742  DCHECK(it.HasAccess());
2743  it.Next();
2744  }
2745  // Skip past the interceptor on the receiver.
2746  DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2747  it.Next();
2748 
2749  MAYBE_RETURN(
2750  Object::SetProperty(&it, value, language_mode, StoreOrigin::kNamed),
2751  ReadOnlyRoots(isolate).exception());
2752  return *value;
2753 }
2754 
2755 
2756 RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2757  // TODO(verwaest): This should probably get the holder and receiver as input.
2758  HandleScope scope(isolate);
2759  Handle<JSObject> receiver = args.at<JSObject>(0);
2760  DCHECK_GE(args.smi_at(1), 0);
2761  uint32_t index = args.smi_at(1);
2762 
2763  Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
2764  isolate);
2765  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2766  *receiver, kDontThrow);
2767  Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
2768 
2769  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2770 
2771  if (result.is_null()) {
2772  LookupIterator it(isolate, receiver, index, receiver);
2773  DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2774  it.Next();
2775  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2776  Object::GetProperty(&it));
2777  }
2778 
2779  return *result;
2780 }
2781 } // namespace internal
2782 } // namespace v8
Definition: libplatform.h:13