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