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