ic.cc 120 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/ic/ic.h"
6

7 8
#include <iostream>

9
#include "src/accessors.h"
10
#include "src/api-arguments-inl.h"
11 12
#include "src/api.h"
#include "src/arguments.h"
13
#include "src/base/bits.h"
14 15 16
#include "src/codegen.h"
#include "src/conversions.h"
#include "src/execution.h"
17
#include "src/field-type.h"
18
#include "src/frames-inl.h"
19
#include "src/ic/call-optimization.h"
20
#include "src/ic/handler-compiler.h"
21
#include "src/ic/handler-configuration-inl.h"
22
#include "src/ic/ic-inl.h"
23
#include "src/ic/ic-stats.h"
24
#include "src/ic/stub-cache.h"
25
#include "src/isolate-inl.h"
26
#include "src/macro-assembler.h"
27
#include "src/prototype.h"
28
#include "src/runtime-profiler.h"
29
#include "src/runtime/runtime-utils.h"
30
#include "src/runtime/runtime.h"
31
#include "src/tracing/trace-event.h"
32
#include "src/tracing/tracing-category-observer.h"
33

34 35
namespace v8 {
namespace internal {
36

37
char IC::TransitionMarkFromState(IC::State state) {
38
  switch (state) {
39 40 41 42 43 44
    case UNINITIALIZED:
      return '0';
    case PREMONOMORPHIC:
      return '.';
    case MONOMORPHIC:
      return '1';
45
    case RECOMPUTE_HANDLER:
46
      return '^';
47 48 49 50 51 52
    case POLYMORPHIC:
      return 'P';
    case MEGAMORPHIC:
      return 'N';
    case GENERIC:
      return 'G';
53 54 55 56 57
  }
  UNREACHABLE();
  return 0;
}

58 59 60 61 62 63 64 65 66 67

const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
  if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
  if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
    return ".IGNORE_OOB";
  }
  if (IsGrowStoreMode(mode)) return ".GROW";
  return "";
}

68
#define TRACE_GENERIC_IC(reason) set_slow_stub_reason(reason);
69

70
void IC::TraceIC(const char* type, Handle<Object> name) {
71
  if (FLAG_ic_stats) {
72
    if (AddressIsDeoptimizedCode()) return;
verwaest's avatar
verwaest committed
73 74
    DCHECK(UseVector());
    State new_state = nexus()->StateFromFeedback();
75 76 77 78
    TraceIC(type, name, state(), new_state);
  }
}

79 80
Address IC::GetAbstractPC(int* line, int* column) const {
  JavaScriptFrameIterator it(isolate());
81

82 83 84
  JavaScriptFrame* frame = it.frame();
  DCHECK(!frame->is_builtin());
  int position = frame->position();
85

86 87 88 89 90 91 92
  Object* maybe_script = frame->function()->shared()->script();
  if (maybe_script->IsScript()) {
    Handle<Script> script(Script::cast(maybe_script), isolate());
    Script::PositionInfo info;
    Script::GetPositionInfo(script, position, &info, Script::WITH_OFFSET);
    *line = info.line + 1;
    *column = info.column + 1;
93
  } else {
94 95
    *line = position;
    *column = -1;
96
  }
97

98 99 100 101 102 103 104
  if (frame->is_interpreted()) {
    InterpretedFrame* iframe = static_cast<InterpretedFrame*>(frame);
    Address bytecode_start =
        reinterpret_cast<Address>(iframe->GetBytecodeArray()) - kHeapObjectTag +
        BytecodeArray::kHeaderSize;
    return bytecode_start + iframe->GetBytecodeOffset();
  }
105

106 107 108 109 110 111 112 113 114 115
  return frame->pc();
}

void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
                 State new_state) {
  if (V8_LIKELY(!FLAG_ic_stats)) return;

  Map* map = nullptr;
  if (!receiver_map().is_null()) {
    map = *receiver_map();
116
  }
117

118
  const char* modifier = "";
119
  if (IsKeyedStoreIC()) {
120 121 122 123
    KeyedAccessStoreMode mode =
        casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
    modifier = GetTransitionMarkModifier(mode);
  }
124 125 126 127 128 129 130 131 132 133 134

  if (!(FLAG_ic_stats &
        v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
    int line;
    int column;
    Address pc = GetAbstractPC(&line, &column);
    LOG(isolate(), ICEvent(type, is_keyed(), pc, line, column, map, *name,
                           TransitionMarkFromState(old_state),
                           TransitionMarkFromState(new_state), modifier,
                           slow_stub_reason_));
    return;
135
  }
136 137 138 139 140 141 142 143 144 145 146 147 148

  ICStats::instance()->Begin();
  ICInfo& ic_info = ICStats::instance()->Current();
  ic_info.type = is_keyed() ? "Keyed" : "";
  ic_info.type += type;

  Object* maybe_function =
      Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
  DCHECK(maybe_function->IsJSFunction());
  JSFunction* function = JSFunction::cast(maybe_function);
  int code_offset = 0;
  if (function->IsInterpreted()) {
    code_offset = InterpretedFrame::GetBytecodeOffset(fp());
149
  } else {
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    code_offset =
        static_cast<int>(pc() - function->code()->instruction_start());
  }
  JavaScriptFrame::CollectFunctionAndOffsetForICStats(
      function, function->abstract_code(), code_offset);

  // Reserve enough space for IC transition state, the longest length is 17.
  ic_info.state.reserve(17);
  ic_info.state = "(";
  ic_info.state += TransitionMarkFromState(old_state);
  ic_info.state += "->";
  ic_info.state += TransitionMarkFromState(new_state);
  ic_info.state += modifier;
  ic_info.state += ")";
  ic_info.map = reinterpret_cast<void*>(map);
165
  if (map != nullptr) {
166 167 168
    ic_info.is_dictionary_map = map->is_dictionary_map();
    ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
    ic_info.instance_type = std::to_string(map->instance_type());
169
  }
170 171
  // TODO(lpy) Add name as key field in ICStats.
  ICStats::instance()->End();
172
}
173

174

175
#define TRACE_IC(type, name) TraceIC(type, name)
176

177
IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
178
    : isolate_(isolate),
179
      vector_set_(false),
180
      kind_(FeedbackSlotKind::kInvalid),
181
      target_maps_set_(false),
182
      slow_stub_reason_(nullptr),
183
      nexus_(nexus) {
184 185 186
  // To improve the performance of the (much used) IC code, we unfold a few
  // levels of the stack frame iteration code. This yields a ~35% speedup when
  // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
187
  const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
188 189 190 191
  Address* constant_pool = NULL;
  if (FLAG_enable_embedded_constant_pool) {
    constant_pool = reinterpret_cast<Address*>(
        entry + ExitFrameConstants::kConstantPoolOffset);
192
  }
193 194 195 196 197 198 199
  Address* pc_address =
      reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
  Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
  // If there's another JavaScript frame on the stack or a
  // StubFailureTrampoline, we need to look one frame further down the stack to
  // find the frame pointer and the return address stack slot.
  if (depth == EXTRA_CALL_FRAME) {
200 201 202
    if (FLAG_enable_embedded_constant_pool) {
      constant_pool = reinterpret_cast<Address*>(
          fp + StandardFrameConstants::kConstantPoolOffset);
203
    }
204 205 206 207 208
    const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
    pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
  }
#ifdef DEBUG
209
  StackFrameIterator it(isolate);
210 211
  for (int i = 0; i < depth + 1; i++) it.Advance();
  StackFrame* frame = it.frame();
212
  DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
213
#endif
214 215 216 217 218
  // For interpreted functions, some bytecode handlers construct a
  // frame. We have to skip the constructed frame to find the interpreted
  // function's frame. Check if the there is an additional frame, and if there
  // is skip this frame. However, the pc should not be updated. The call to
  // ICs happen from bytecode handlers.
219 220 221
  intptr_t frame_marker =
      Memory::intptr_at(fp + TypedFrameConstants::kFrameTypeOffset);
  if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
222 223
    fp = Memory::Address_at(fp + TypedFrameConstants::kCallerFPOffset);
  }
224
  fp_ = fp;
225 226
  if (FLAG_enable_embedded_constant_pool) {
    constant_pool_address_ = constant_pool;
227
  }
228
  pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
229 230 231 232 233 234 235 236 237
  if (nexus) {
    kind_ = nexus->kind();
    DCHECK(UseVector());
    state_ = nexus->StateFromFeedback();
    extra_ic_state_ = kNoExtraICState;
  } else {
    Code* target = this->target();
    Code::Kind kind = target->kind();
    if (kind == Code::BINARY_OP_IC) {
238
      kind_ = FeedbackSlotKind::kBinaryOp;
239
    } else if (kind == Code::COMPARE_IC) {
240
      kind_ = FeedbackSlotKind::kCompareOp;
241
    } else if (kind == Code::TO_BOOLEAN_IC) {
242
      kind_ = FeedbackSlotKind::kToBoolean;
243 244
    } else {
      UNREACHABLE();
245
      kind_ = FeedbackSlotKind::kInvalid;
246 247 248 249 250
    }
    DCHECK(!UseVector());
    state_ = StateFromCode(target);
    extra_ic_state_ = target->extra_ic_state();
  }
251
  old_state_ = state_;
252 253
}

254 255 256 257
// The ICs that don't pass slot and vector through the stack have to
// save/restore them in the dispatcher.
bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) {
  if (kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
258
      kind == Code::KEYED_LOAD_IC) {
259 260 261 262 263 264 265 266
    return true;
  }
  if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
    return !StoreWithVectorDescriptor::kPassLastArgsOnStack;
  }
  return false;
}

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
InlineCacheState IC::StateFromCode(Code* code) {
  Isolate* isolate = code->GetIsolate();
  switch (code->kind()) {
    case Code::BINARY_OP_IC: {
      BinaryOpICState state(isolate, code->extra_ic_state());
      return state.GetICState();
    }
    case Code::COMPARE_IC: {
      CompareICStub stub(isolate, code->extra_ic_state());
      return stub.GetICState();
    }
    case Code::TO_BOOLEAN_IC: {
      ToBooleanICStub stub(isolate, code->extra_ic_state());
      return stub.GetICState();
    }
    default:
      if (code->is_debug_stub()) return UNINITIALIZED;
      UNREACHABLE();
      return UNINITIALIZED;
  }
}
288

289
JSFunction* IC::GetHostFunction() const {
290 291 292
  // Compute the JavaScript frame for the frame pointer of this IC
  // structure. We need this to be able to find the function
  // corresponding to the frame.
293
  StackFrameIterator it(isolate());
294 295 296 297
  while (it.frame()->fp() != this->fp()) it.Advance();
  JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
  // Find the function on the stack and both the active code for the
  // function and the original code.
298
  return frame->function();
299 300
}

301 302 303 304
static void LookupForRead(LookupIterator* it) {
  for (; it->IsFound(); it->Next()) {
    switch (it->state()) {
      case LookupIterator::NOT_FOUND:
305
      case LookupIterator::TRANSITION:
306 307 308 309 310 311
        UNREACHABLE();
      case LookupIterator::JSPROXY:
        return;
      case LookupIterator::INTERCEPTOR: {
        // If there is a getter, return; otherwise loop to perform the lookup.
        Handle<JSObject> holder = it->GetHolder<JSObject>();
312 313
        if (!holder->GetNamedInterceptor()->getter()->IsUndefined(
                it->isolate())) {
314 315 316 317 318
          return;
        }
        break;
      }
      case LookupIterator::ACCESS_CHECK:
319 320
        // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
        // access checks for global proxies.
321
        if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
322 323
          break;
        }
324
        return;
325
      case LookupIterator::ACCESSOR:
326
      case LookupIterator::INTEGER_INDEXED_EXOTIC:
327 328
      case LookupIterator::DATA:
        return;
329 330 331 332
    }
  }
}

333
bool IC::ShouldRecomputeHandler(Handle<String> name) {
334
  if (!RecomputeHandlerForName(name)) return false;
335

verwaest's avatar
verwaest committed
336 337
  DCHECK(UseVector());
  maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
338

339 340
  // This is a contextual access, always just update the handler and stay
  // monomorphic.
341
  if (IsLoadGlobalIC()) return true;
342

343 344 345 346 347 348
  // The current map wasn't handled yet. There's no reason to stay monomorphic,
  // *unless* we're moving from a deprecated map to its replacement, or
  // to a more general elements kind.
  // TODO(verwaest): Check if the current map is actually what the old map
  // would transition to.
  if (maybe_handler_.is_null()) {
349
    if (!receiver_map()->IsJSObjectMap()) return false;
350 351 352 353
    Map* first_map = FirstTargetMap();
    if (first_map == NULL) return false;
    Handle<Map> old_map(first_map);
    if (old_map->is_deprecated()) return true;
354 355
    return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
                                               receiver_map()->elements_kind());
356
  }
357

358
  return true;
359 360
}

361
bool IC::RecomputeHandlerForName(Handle<Object> name) {
verwaest's avatar
verwaest committed
362
  if (is_keyed()) {
363 364
    // Determine whether the failure is due to a name failure.
    if (!name->IsName()) return false;
verwaest's avatar
verwaest committed
365 366
    DCHECK(UseVector());
    Name* stub_name = nexus()->FindFirstName();
367 368 369 370 371 372 373
    if (*name != stub_name) return false;
  }

  return true;
}


374
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
375
  update_receiver_map(receiver);
376
  if (!name->IsString()) return;
377
  if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
378
  if (receiver->IsNullOrUndefined(isolate())) return;
379 380 381 382

  // Remove the target from the code cache if it became invalid
  // because of changes in the prototype chain to avoid hitting it
  // again.
383
  if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
384
    MarkRecomputeHandler(name);
385 386 387 388
  }
}


389 390
MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
                                  Handle<Object> object, Handle<Object> key) {
391
  HandleScope scope(isolate());
392
  THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
393 394 395
}


396
MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
397
  HandleScope scope(isolate());
398 399
  THROW_NEW_ERROR(
      isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
400 401 402
}


403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
                                      int* polymorphic_delta,
                                      int* generic_delta) {
  switch (old_state) {
    case UNINITIALIZED:
    case PREMONOMORPHIC:
      if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
      if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
        *polymorphic_delta = 1;
      } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
        *generic_delta = 1;
      }
      break;
    case MONOMORPHIC:
    case POLYMORPHIC:
      if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
      *polymorphic_delta = -1;
      if (new_state == MEGAMORPHIC || new_state == GENERIC) {
        *generic_delta = 1;
      }
      break;
    case MEGAMORPHIC:
    case GENERIC:
      if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
      *generic_delta = -1;
      if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
        *polymorphic_delta = 1;
      }
      break;
432
    case RECOMPUTE_HANDLER:
433 434
      UNREACHABLE();
  }
435 436
}

437
// static
438 439
void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) {
  Code* host = host_function->shared()->code();
440

441 442 443 444 445
  if (host->kind() == Code::FUNCTION) {
    TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
    info->change_own_type_change_checksum();
    host->set_profiler_ticks(0);
  }
446 447 448 449 450 451
  isolate->runtime_profiler()->NotifyICChanged();
  // TODO(2029): When an optimized function is patched, it would
  // be nice to propagate the corresponding type information to its
  // unoptimized version for the benefit of later inlining.
}

452 453 454
void IC::PostPatching(Address address, Code* target, Code* old_target) {
  // Type vector based ICs update these statistics at a different time because
  // they don't always patch on state change.
455
  // TODO(ishell): DCHECK
456
  if (ICUseVector(target->kind())) return;
457

verwaest's avatar
verwaest committed
458 459
  DCHECK(old_target->is_inline_cache_stub());
  DCHECK(target->is_inline_cache_stub());
460 461
  State old_state = StateFromCode(old_target);
  State new_state = StateFromCode(target);
462

verwaest's avatar
verwaest committed
463 464 465 466
  Isolate* isolate = target->GetIsolate();
  Code* host =
      isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
  if (host->kind() != Code::FUNCTION) return;
467

verwaest's avatar
verwaest committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
  // Not all Code objects have TypeFeedbackInfo.
  if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
    if (FLAG_type_info_threshold > 0) {
      int polymorphic_delta = 0;  // "Polymorphic" here includes monomorphic.
      int generic_delta = 0;      // "Generic" here includes megamorphic.
      ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
                                &generic_delta);
      TypeFeedbackInfo* info =
          TypeFeedbackInfo::cast(host->type_feedback_info());
      info->change_ic_with_type_info_count(polymorphic_delta);
      info->change_ic_generic_count(generic_delta);
    }
    TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
    info->change_own_type_change_checksum();
  }
  host->set_profiler_ticks(0);
  isolate->runtime_profiler()->NotifyICChanged();
  // TODO(2029): When an optimized function is patched, it would
  // be nice to propagate the corresponding type information to its
  // unoptimized version for the benefit of later inlining.
}
489

490
void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
491
  Code* target = GetTargetAtAddress(address, constant_pool);
492 493

  // Don't clear debug break inline cache as it will remove the break point.
494
  if (target->is_debug_stub()) return;
495

verwaest's avatar
verwaest committed
496 497
  if (target->kind() == Code::COMPARE_IC) {
    CompareIC::Clear(isolate, address, target, constant_pool);
498 499 500
  }
}

501
void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
502
                      Address constant_pool) {
503
  DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
504
  CompareICStub stub(target->stub_key(), isolate);
505
  // Only clear CompareICs that can retain objects.
506
  if (stub.state() != CompareICState::KNOWN_RECEIVER) return;
507
  SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
508
                     constant_pool);
509
  PatchInlinedSmiCode(isolate, address, DISABLE_INLINED_SMI_CHECK);
510 511
}

512 513 514 515 516 517 518 519
static bool MigrateDeprecated(Handle<Object> object) {
  if (!object->IsJSObject()) return false;
  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
  if (!receiver->map()->is_deprecated()) return false;
  JSObject::MigrateInstance(Handle<JSObject>::cast(object));
  return true;
}

520
void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
521
  DCHECK(UseVector());
522 523 524
  if (new_state == PREMONOMORPHIC) {
    nexus()->ConfigurePremonomorphic();
  } else if (new_state == MEGAMORPHIC) {
525
    if (IsLoadIC() || IsStoreIC() || IsStoreOwnIC()) {
526
      nexus()->ConfigureMegamorphic();
527
    } else if (IsKeyedLoadIC()) {
528 529 530
      KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
      nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
    } else {
531
      DCHECK(IsKeyedStoreIC());
532 533 534
      KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
      nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
    }
535 536 537 538
  } else {
    UNREACHABLE();
  }

539
  vector_set_ = true;
540
  OnFeedbackChanged(isolate(), GetHostFunction());
541 542
}

543
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
544
                              Handle<Object> handler) {
545
  DCHECK(UseVector());
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
  switch (kind_) {
    case FeedbackSlotKind::kLoadProperty: {
      LoadICNexus* nexus = casted_nexus<LoadICNexus>();
      nexus->ConfigureMonomorphic(map, handler);
      break;
    }
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
      LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
      nexus->ConfigureHandlerMode(handler);
      break;
    }
    case FeedbackSlotKind::kLoadKeyed: {
      KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
      nexus->ConfigureMonomorphic(name, map, handler);
      break;
    }
    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreOwnNamed: {
      StoreICNexus* nexus = casted_nexus<StoreICNexus>();
      nexus->ConfigureMonomorphic(map, handler);
      break;
    }
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict: {
      KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
      nexus->ConfigureMonomorphic(name, map, handler);
      break;
    }
    case FeedbackSlotKind::kCall:
    case FeedbackSlotKind::kBinaryOp:
    case FeedbackSlotKind::kCompareOp:
    case FeedbackSlotKind::kToBoolean:
    case FeedbackSlotKind::kCreateClosure:
    case FeedbackSlotKind::kLiteral:
    case FeedbackSlotKind::kGeneral:
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
      break;
588 589
  }

590
  vector_set_ = true;
591
  OnFeedbackChanged(isolate(), GetHostFunction());
592 593
}

594
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
595
                              List<Handle<Object>>* handlers) {
596
  DCHECK(UseVector());
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
  switch (kind_) {
    case FeedbackSlotKind::kLoadProperty: {
      LoadICNexus* nexus = casted_nexus<LoadICNexus>();
      nexus->ConfigurePolymorphic(maps, handlers);
      break;
    }
    case FeedbackSlotKind::kLoadKeyed: {
      KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
      nexus->ConfigurePolymorphic(name, maps, handlers);
      break;
    }
    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreOwnNamed: {
      StoreICNexus* nexus = casted_nexus<StoreICNexus>();
      nexus->ConfigurePolymorphic(maps, handlers);
      break;
    }
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict: {
      KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
      nexus->ConfigurePolymorphic(name, maps, handlers);
      break;
    }
    case FeedbackSlotKind::kCall:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    case FeedbackSlotKind::kBinaryOp:
    case FeedbackSlotKind::kCompareOp:
    case FeedbackSlotKind::kToBoolean:
    case FeedbackSlotKind::kCreateClosure:
    case FeedbackSlotKind::kLiteral:
    case FeedbackSlotKind::kGeneral:
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
      break;
635 636
  }

637
  vector_set_ = true;
638
  OnFeedbackChanged(isolate(), GetHostFunction());
639 640
}

641 642
void IC::ConfigureVectorState(MapHandleList* maps,
                              MapHandleList* transitioned_maps,
643
                              List<Handle<Object>>* handlers) {
644
  DCHECK(UseVector());
645
  DCHECK(IsKeyedStoreIC());
646 647 648 649
  KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
  nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);

  vector_set_ = true;
650
  OnFeedbackChanged(isolate(), GetHostFunction());
651 652 653
}


654
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
655 656
  // If the object is undefined or null it's illegal to try to get any
  // of its properties; throw a TypeError in that case.
657
  if (object->IsNullOrUndefined(isolate())) {
658 659 660 661 662 663 664
    if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) {
      // Ensure the IC state progresses.
      TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
      update_receiver_map(object);
      PatchCache(name, slow_stub());
      TRACE_IC("LoadIC", name);
    }
665
    return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
666 667
  }

668
  bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
669

670 671
  if (state() != UNINITIALIZED) {
    JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
672
    update_receiver_map(object);
673
  }
674
  // Named lookup in the object.
675 676
  LookupIterator it(object, name);
  LookupForRead(&it);
677

678
  if (it.IsFound() || !ShouldThrowReferenceError()) {
679 680
    // Update inline cache and stub cache.
    if (use_ic) UpdateCaches(&it);
681

682 683
    // Get the property.
    Handle<Object> result;
684

685 686
    ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
                               Object);
687 688
    if (it.IsFound()) {
      return result;
689
    } else if (!ShouldThrowReferenceError()) {
690 691 692
      LOG(isolate(), SuspectReadEvent(*name, *object));
      return result;
    }
693
  }
694
  return ReferenceError(name);
695 696
}

697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
  Handle<JSGlobalObject> global = isolate()->global_object();

  if (name->IsString()) {
    // Look up in script context table.
    Handle<String> str_name = Handle<String>::cast(name);
    Handle<ScriptContextTable> script_contexts(
        global->native_context()->script_context_table());

    ScriptContextTable::LookupResult lookup_result;
    if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
      Handle<Object> result =
          FixedArray::get(*ScriptContextTable::GetContext(
                              script_contexts, lookup_result.context_index),
                          lookup_result.slot_index, isolate());
      if (result->IsTheHole(isolate())) {
        // Do not install stubs and stay pre-monomorphic for
        // uninitialized accesses.
        return ReferenceError(name);
      }

      if (FLAG_use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub);
        LoadScriptContextFieldStub stub(isolate(), &lookup_result);
        PatchCache(name, stub.GetCode());
        TRACE_IC("LoadGlobalIC", name);
      }
      return result;
    }
  }
  return LoadIC::Load(global, name);
}
729

730 731
static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
                                       Handle<Map> new_receiver_map) {
732
  DCHECK(!new_receiver_map.is_null());
733 734 735 736 737 738 739 740 741 742
  for (int current = 0; current < receiver_maps->length(); ++current) {
    if (!receiver_maps->at(current).is_null() &&
        receiver_maps->at(current).is_identical_to(new_receiver_map)) {
      return false;
    }
  }
  receiver_maps->Add(new_receiver_map);
  return true;
}

743 744
bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
  DCHECK(IsHandler(*handler));
verwaest's avatar
verwaest committed
745
  if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
746 747
  Handle<Map> map = receiver_map();
  MapHandleList maps;
748
  List<Handle<Object>> handlers;
749

750 751 752
  TargetMaps(&maps);
  int number_of_maps = maps.length();
  int deprecated_maps = 0;
753
  int handler_to_overwrite = -1;
754

755 756 757
  for (int i = 0; i < number_of_maps; i++) {
    Handle<Map> current_map = maps.at(i);
    if (current_map->is_deprecated()) {
758
      // Filter out deprecated maps to ensure their instances get migrated.
759 760
      ++deprecated_maps;
    } else if (map.is_identical_to(current_map)) {
761 762 763 764
      // If the receiver type is already in the polymorphic IC, this indicates
      // there was a prototoype chain failure. In that case, just overwrite the
      // handler.
      handler_to_overwrite = i;
765 766
    } else if (handler_to_overwrite == -1 &&
               IsTransitionOfMonomorphicTarget(*current_map, *map)) {
767
      handler_to_overwrite = i;
768
    }
769
  }
770

771 772
  int number_of_valid_maps =
      number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
773

774 775
  if (number_of_valid_maps >= 4) return false;
  if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
776 777
    return false;
  }
verwaest's avatar
verwaest committed
778 779
  DCHECK(UseVector());
  if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
780

781
  number_of_valid_maps++;
verwaest's avatar
verwaest committed
782
  if (number_of_valid_maps > 1 && is_keyed()) return false;
783
  if (number_of_valid_maps == 1) {
784
    ConfigureVectorState(name, receiver_map(), handler);
785
  } else {
786
    if (handler_to_overwrite >= 0) {
787
      handlers.Set(handler_to_overwrite, handler);
788 789
      if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
        maps.Set(handler_to_overwrite, map);
790 791
      }
    } else {
792
      maps.Add(map);
793
      handlers.Add(handler);
794
    }
795

796
    ConfigureVectorState(name, &maps, &handlers);
797
  }
798

799 800 801
  return true;
}

802
void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
803
  DCHECK(IsHandler(*handler));
804
  ConfigureVectorState(name, receiver_map(), handler);
805 806 807
}


808
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
809
  MapHandleList maps;
810
  List<Handle<Object>> handlers;
811
  TargetMaps(&maps);
verwaest's avatar
verwaest committed
812
  if (!nexus()->FindHandlers(&handlers, maps.length())) return;
813 814
  for (int i = 0; i < maps.length(); i++) {
    UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
815 816 817 818
  }
}


819 820 821 822
bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
  if (source_map == NULL) return true;
  if (target_map == NULL) return false;
  ElementsKind target_elements_kind = target_map->elements_kind();
823 824
  bool more_general_transition = IsMoreGeneralElementsKindTransition(
      source_map->elements_kind(), target_elements_kind);
825 826 827 828 829 830
  Map* transitioned_map = nullptr;
  if (more_general_transition) {
    MapHandleList map_list;
    map_list.Add(handle(target_map));
    transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list);
  }
831
  return transitioned_map == target_map;
832 833
}

834 835
void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
  DCHECK(IsHandler(*handler));
836 837
  // Currently only load and store ICs support non-code handlers.
  DCHECK_IMPLIES(!handler->IsCode(), IsAnyLoad() || IsAnyStore());
838
  switch (state()) {
839 840
    case UNINITIALIZED:
    case PREMONOMORPHIC:
841
      UpdateMonomorphicIC(handler, name);
842
      break;
843
    case RECOMPUTE_HANDLER:
844
    case MONOMORPHIC:
845
      if (IsLoadGlobalIC()) {
846
        UpdateMonomorphicIC(handler, name);
847 848 849
        break;
      }
    // Fall through.
850
    case POLYMORPHIC:
verwaest's avatar
verwaest committed
851
      if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
852
        if (UpdatePolymorphicIC(name, handler)) break;
853 854
        // For keyed stubs, we can't know whether old handlers were for the
        // same key.
855
        CopyICToMegamorphicCache(name);
856
      }
verwaest's avatar
verwaest committed
857
      DCHECK(UseVector());
858
      ConfigureVectorState(MEGAMORPHIC, name);
859
    // Fall through.
860
    case MEGAMORPHIC:
861
      UpdateMegamorphicCache(*receiver_map(), *name, *handler);
862
      // Indicate that we've handled this case.
verwaest's avatar
verwaest committed
863 864
      DCHECK(UseVector());
      vector_set_ = true;
865
      break;
866
    case GENERIC:
867
      UNREACHABLE();
868
      break;
869
  }
870 871
}

872 873 874
Handle<Object> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
  TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH);
  return LoadHandler::LoadField(isolate, index);
875 876
}

877 878
namespace {

879
template <bool fill_array = true>
880
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
881 882
                        Handle<JSObject> holder, Handle<Name> name,
                        Handle<FixedArray> array, int first_index) {
883
  DCHECK(holder.is_null() || holder->HasFastProperties());
884

885 886 887
  // We don't encode the requirement to check access rights because we already
  // passed the access check for current native context and the access
  // can't be revoked.
888

889 890 891
  HandleScope scope(isolate);
  int checks_count = 0;

892 893 894 895 896 897 898 899 900 901 902 903 904
  if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
    // The validity cell check for primitive and global proxy receivers does
    // not guarantee that certain native context ever had access to other
    // native context. However, a handler created for one native context could
    // be used in other native context through the megamorphic stub cache.
    // So we record the original native context to which this handler
    // corresponds.
    if (fill_array) {
      Handle<Context> native_context = isolate->native_context();
      array->set(LoadHandler::kFirstPrototypeIndex + checks_count,
                 native_context->self_weak_cell());
    }
    checks_count++;
905 906 907 908 909 910 911 912 913 914 915

  } else if (receiver_map->IsJSGlobalObjectMap()) {
    if (fill_array) {
      Handle<JSGlobalObject> global = isolate->global_object();
      Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
          global, name, PropertyCellType::kInvalidated);
      DCHECK(cell->value()->IsTheHole(isolate));
      Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
      array->set(LoadHandler::kFirstPrototypeIndex + checks_count, *weak_cell);
    }
    checks_count++;
916 917
  }

918 919
  // Create/count entries for each global or dictionary prototype appeared in
  // the prototype chain contains from receiver till holder.
920 921 922 923 924
  PrototypeIterator::WhereToEnd end = name->IsPrivate()
                                          ? PrototypeIterator::END_AT_NON_HIDDEN
                                          : PrototypeIterator::END_AT_NULL;
  for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
       iter.Advance()) {
925
    Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
926
    if (holder.is_identical_to(current)) break;
927 928
    Handle<Map> current_map(current->map(), isolate);

929
    if (current_map->IsJSGlobalObjectMap()) {
930 931 932 933 934 935
      if (fill_array) {
        Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current);
        Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
            global, name, PropertyCellType::kInvalidated);
        DCHECK(cell->value()->IsTheHole(isolate));
        Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
936
        array->set(first_index + checks_count, *weak_cell);
937 938 939
      }
      checks_count++;

940 941
    } else if (current_map->is_dictionary_map()) {
      DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
942 943 944 945 946
      if (fill_array) {
        DCHECK_EQ(NameDictionary::kNotFound,
                  current->property_dictionary()->FindEntry(name));
        Handle<WeakCell> weak_cell =
            Map::GetOrCreatePrototypeWeakCell(current, isolate);
947
        array->set(first_index + checks_count, *weak_cell);
948 949
      }
      checks_count++;
950 951
    }
  }
952 953 954
  return checks_count;
}

955 956 957 958 959 960 961
// Returns 0 if the validity cell check is enough to ensure that the
// prototype chain from |receiver_map| till |holder| did not change.
// If the |holder| is an empty handle then the full prototype chain is
// checked.
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
962 963 964
                           Handle<JSObject> holder, Handle<Name> name) {
  return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
                                    Handle<FixedArray>(), 0);
965 966
}

967 968
}  // namespace

969 970 971 972
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
                                         Handle<JSObject> holder,
                                         Handle<Name> name,
                                         Handle<Object> smi_handler) {
973 974
  int checks_count =
      GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
975
  DCHECK_LE(0, checks_count);
976

977 978 979 980 981
  if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
    DCHECK(!receiver_map->is_dictionary_map());
    DCHECK_LE(1, checks_count);  // For native context.
    smi_handler =
        LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
982 983
  } else if (receiver_map->is_dictionary_map() &&
             !receiver_map->IsJSGlobalObjectMap()) {
984 985 986 987
    smi_handler =
        LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler);
  }

988 989 990 991
  Handle<Cell> validity_cell =
      Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
  DCHECK(!validity_cell.is_null());

992 993
  Handle<WeakCell> holder_cell =
      Map::GetOrCreatePrototypeWeakCell(holder, isolate());
994 995 996 997 998 999 1000 1001 1002 1003

  if (checks_count == 0) {
    return isolate()->factory()->NewTuple3(holder_cell, smi_handler,
                                           validity_cell);
  }
  Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray(
      LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
  handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
  handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
  handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell);
1004
  InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
1005
                      LoadHandler::kFirstPrototypeIndex);
1006
  return handler_array;
1007
}
1008

1009 1010
Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
                                       Handle<Name> name) {
1011
  Handle<JSObject> holder;  // null handle
1012 1013
  int checks_count =
      GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
1014 1015
  DCHECK_LE(0, checks_count);

1016 1017 1018 1019
  bool do_negative_lookup_on_receiver =
      receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap();
  Handle<Object> smi_handler =
      LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver);
1020

1021 1022 1023 1024 1025 1026 1027
  if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
    DCHECK(!receiver_map->is_dictionary_map());
    DCHECK_LE(1, checks_count);  // For native context.
    smi_handler =
        LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
  }

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
  Handle<Object> validity_cell =
      Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
  if (validity_cell.is_null()) {
    DCHECK_EQ(0, checks_count);
    validity_cell = handle(Smi::FromInt(0), isolate());
  }

  Factory* factory = isolate()->factory();
  if (checks_count == 0) {
    return factory->NewTuple3(factory->null_value(), smi_handler,
                              validity_cell);
  }
  Handle<FixedArray> handler_array(factory->NewFixedArray(
      LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
  handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
  handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
  handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value());
1045
  InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
1046
                      LoadHandler::kFirstPrototypeIndex);
1047 1048 1049
  return handler_array;
}

1050 1051 1052 1053
bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
  DCHECK(lookup->state() == LookupIterator::ACCESSOR);
  Isolate* isolate = lookup->isolate();
  Handle<Object> accessors = lookup->GetAccessors();
1054 1055
  if (accessors->IsAccessorInfo()) {
    Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1056
    if (info->getter() != NULL &&
1057
        !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) {
1058 1059 1060 1061 1062
      return false;
    }
  } else if (accessors->IsAccessorPair()) {
    Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
                          isolate);
1063
    if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
1064
      return false;
1065
    }
1066 1067
    Handle<JSObject> holder = lookup->GetHolder<JSObject>();
    Handle<Object> receiver = lookup->GetReceiver();
1068 1069 1070
    if (holder->HasFastProperties()) {
      if (getter->IsJSFunction()) {
        Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1071
        if (!receiver->IsJSObject() && function->shared()->IsUserJavaScript() &&
1072 1073 1074
            is_sloppy(function->shared()->language_mode())) {
          // Calling sloppy non-builtins with a value as the receiver
          // requires boxing.
1075 1076 1077
          return false;
        }
      }
1078 1079 1080 1081 1082
      CallOptimization call_optimization(getter);
      if (call_optimization.is_simple_api_call() &&
          !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) {
        return false;
      }
1083 1084 1085 1086 1087 1088
    }
  }
  return true;
}


1089
void LoadIC::UpdateCaches(LookupIterator* lookup) {
1090
  if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
1091 1092
    // This is the first time we execute this inline cache. Set the target to
    // the pre monomorphic stub to delay setting the monomorphic state.
1093
    TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
1094
    ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
1095
    TRACE_IC("LoadIC", lookup->name());
1096
    return;
1097 1098
  }

1099
  Handle<Object> code;
1100 1101
  if (lookup->state() == LookupIterator::JSPROXY ||
      lookup->state() == LookupIterator::ACCESS_CHECK) {
1102
    code = slow_stub();
1103
  } else if (!lookup->IsFound()) {
1104 1105
    TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
    code = LoadNonExistent(receiver_map(), lookup->name());
1106
  } else {
1107
    if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA &&
1108 1109
        lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
      DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
1110 1111 1112 1113 1114 1115
      // Now update the cell in the feedback vector.
      LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
      nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
      TRACE_IC("LoadGlobalIC", lookup->name());
      return;
    } else if (lookup->state() == LookupIterator::ACCESSOR) {
1116
      if (!IsCompatibleReceiver(lookup, receiver_map())) {
1117
        TRACE_GENERIC_IC("incompatible receiver type");
1118 1119 1120
        code = slow_stub();
      }
    } else if (lookup->state() == LookupIterator::INTERCEPTOR) {
1121 1122 1123 1124 1125 1126 1127
      // Perform a lookup behind the interceptor. Copy the LookupIterator
      // since the original iterator will be used to fetch the value.
      LookupIterator it = *lookup;
      it.Next();
      LookupForRead(&it);
      if (it.state() == LookupIterator::ACCESSOR &&
          !IsCompatibleReceiver(&it, receiver_map())) {
1128
        TRACE_GENERIC_IC("incompatible receiver type");
1129
        code = slow_stub();
1130 1131 1132
      }
    }
    if (code.is_null()) code = ComputeHandler(lookup);
1133
  }
1134

1135 1136
  PatchCache(lookup->name(), code);
  TRACE_IC("LoadIC", lookup->name());
1137 1138
}

1139
StubCache* IC::stub_cache() {
1140 1141 1142 1143 1144
  if (IsAnyLoad()) {
    return isolate()->load_stub_cache();
  } else {
    DCHECK(IsAnyStore());
    return isolate()->store_stub_cache();
1145 1146
  }
}
1147

1148 1149
void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
  stub_cache()->Set(name, map, handler);
1150 1151
}

1152 1153 1154
void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
  if (!FLAG_runtime_call_stats) return;

1155
  if (IsAnyLoad()) {
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
    switch (lookup->state()) {
      case LookupIterator::ACCESS_CHECK:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck);
        break;
      case LookupIterator::INTEGER_INDEXED_EXOTIC:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Exotic);
        break;
      case LookupIterator::INTERCEPTOR:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Interceptor);
        break;
      case LookupIterator::JSPROXY:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_JSProxy);
        break;
      case LookupIterator::NOT_FOUND:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_NonExistent);
        break;
      case LookupIterator::ACCESSOR:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
        break;
      case LookupIterator::DATA:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Data);
        break;
      case LookupIterator::TRANSITION:
        TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition);
        break;
    }
1182
  } else if (IsAnyStore()) {
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
    switch (lookup->state()) {
      case LookupIterator::ACCESS_CHECK:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck);
        break;
      case LookupIterator::INTEGER_INDEXED_EXOTIC:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Exotic);
        break;
      case LookupIterator::INTERCEPTOR:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Interceptor);
        break;
      case LookupIterator::JSPROXY:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_JSProxy);
        break;
      case LookupIterator::NOT_FOUND:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_NonExistent);
        break;
      case LookupIterator::ACCESSOR:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
        break;
      case LookupIterator::DATA:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Data);
        break;
      case LookupIterator::TRANSITION:
        TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Transition);
        break;
    }
  } else {
    TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
  }
}

1214 1215
Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
                                  Handle<Object> value) {
1216
  // Try to find a globally shared handler stub.
1217 1218 1219 1220
  Handle<Object> shared_handler = GetMapIndependentHandler(lookup);
  if (!shared_handler.is_null()) {
    DCHECK(IC::IsHandler(*shared_handler));
    return shared_handler;
1221
  }
1222 1223 1224

  // Otherwise check the map's handler cache for a map-specific handler, and
  // compile one if the cache comes up empty.
1225
  bool receiver_is_holder =
1226
      lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1227
  CacheHolderFlag flag;
1228
  Handle<Map> stub_holder_map;
1229
  if (IsAnyLoad()) {
1230 1231 1232
    stub_holder_map = IC::GetHandlerCacheHolder(
        receiver_map(), receiver_is_holder, isolate(), &flag);
  } else {
1233
    DCHECK(IsAnyStore());
1234 1235 1236 1237
    // Store handlers cannot be cached on prototypes.
    flag = kCacheOnReceiver;
    stub_holder_map = receiver_map();
  }
1238

1239
  Handle<Object> handler = PropertyHandlerCompiler::Find(
1240
      lookup->name(), stub_holder_map, handler_kind(), flag);
1241 1242
  // Use the cached value if it exists, and if it is different from the
  // handler that just missed.
1243 1244 1245 1246
  if (!handler.is_null()) {
    Handle<Object> current_handler;
    if (maybe_handler_.ToHandle(&current_handler)) {
      if (!current_handler.is_identical_to(handler)) {
1247
        TraceHandlerCacheHitStats(lookup);
1248
        return handler;
1249
      }
1250
    } else {
1251 1252 1253
      // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
      // In MEGAMORPHIC case, check if the handler in the megamorphic stub
      // cache (which just missed) is different from the cached handler.
1254 1255
      if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
        Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1256 1257
        Object* megamorphic_cached_handler =
            stub_cache()->Get(*lookup->name(), map);
1258
        if (megamorphic_cached_handler != *handler) {
1259
          TraceHandlerCacheHitStats(lookup);
1260
          return handler;
1261
        }
1262
      } else {
1263
        TraceHandlerCacheHitStats(lookup);
1264
        return handler;
1265 1266 1267 1268
      }
    }
  }

1269 1270 1271 1272 1273 1274 1275 1276
  handler = CompileHandler(lookup, value, flag);
  DCHECK(IC::IsHandler(*handler));
  if (handler->IsCode()) {
    Handle<Code> code = Handle<Code>::cast(handler);
    DCHECK_EQ(Code::ExtractCacheHolderFromFlags(code->flags()), flag);
    Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
  }
  return handler;
1277 1278
}

1279
Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
1280 1281 1282
  Handle<Object> receiver = lookup->GetReceiver();
  if (receiver->IsString() &&
      Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1283
    FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1284
    return SimpleFieldLoad(isolate(), index);
1285 1286
  }

1287 1288
  if (receiver->IsStringWrapper() &&
      Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1289
    TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub);
1290 1291
    StringLengthStub string_length_stub(isolate());
    return string_length_stub.GetCode();
1292 1293
  }

1294
  // Use specialized code for getting prototype of functions.
1295 1296
  if (receiver->IsJSFunction() &&
      Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1297
      receiver->IsConstructor() &&
1298 1299 1300
      !Handle<JSFunction>::cast(receiver)
           ->map()
           ->has_non_instance_prototype()) {
1301
    Handle<Code> stub;
1302
    TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
1303
    return isolate()->builtins()->LoadIC_FunctionPrototype();
1304 1305
  }

1306
  Handle<Map> map = receiver_map();
1307
  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1308
  bool receiver_is_holder = receiver.is_identical_to(holder);
1309
  switch (lookup->state()) {
1310 1311
    case LookupIterator::INTERCEPTOR:
      break;  // Custom-compiled handler.
1312

1313 1314
    case LookupIterator::ACCESSOR: {
      // Use simple field loads for some well-known callback properties.
1315 1316 1317 1318 1319 1320
      // The method will only return true for absolute truths based on the
      // receiver maps.
      int object_offset;
      if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
                                             &object_offset)) {
        FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1321
        return SimpleFieldLoad(isolate(), index);
1322
      }
1323

1324 1325 1326
      if (IsCompatibleReceiver(lookup, map)) {
        Handle<Object> accessors = lookup->GetAccessors();
        if (accessors->IsAccessorPair()) {
1327 1328 1329 1330
          if (!holder->HasFastProperties()) {
            TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
            return slow_stub();
          }
1331
          // When debugging we need to go the slow path to flood the accessor.
1332
          if (GetHostFunction()->shared()->HasDebugInfo()) {
1333 1334
            TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
            return slow_stub();
1335
          }
1336
          break;  // Custom-compiled handler.
1337 1338
        } else if (accessors->IsAccessorInfo()) {
          Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1339 1340 1341
          if (v8::ToCData<Address>(info->getter()) == nullptr) {
            TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
            return slow_stub();
1342
          }
1343 1344
          // Ruled out by IsCompatibleReceiver() above.
          DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
1345 1346 1347
          if (!holder->HasFastProperties() ||
              (info->is_sloppy() && !receiver->IsJSReceiver())) {
            DCHECK(!holder->HasFastProperties() || !receiver_is_holder);
1348 1349 1350
            TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
            return slow_stub();
          }
1351 1352 1353 1354 1355 1356
          Handle<Object> smi_handler =
              LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex());
          if (receiver_is_holder) {
            TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
            return smi_handler;
          }
1357
          if (!IsLoadGlobalIC()) {
1358 1359
            TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
            return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1360
          }
1361
          break;  // Custom-compiled handler.
1362 1363
        }
      }
1364 1365
      TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
      return slow_stub();
1366
    }
1367 1368

    case LookupIterator::DATA: {
1369
      DCHECK_EQ(kData, lookup->property_details().kind());
1370
      if (lookup->is_dictionary_holder()) {
1371
        if (!IsLoadIC() && !IsLoadGlobalIC()) {  // IsKeyedLoadIC()?
1372 1373 1374
          TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
          return slow_stub();
        }
1375
        if (holder->IsJSGlobalObject()) {
1376
          break;  // Custom-compiled handler.
1377 1378 1379 1380 1381
        }
        // There is only one shared stub for loading normalized
        // properties. It does not traverse the prototype chain, so the
        // property must be found in the object for the stub to be
        // applicable.
1382 1383 1384 1385
        if (!receiver_is_holder) {
          TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
          return slow_stub();
        }
1386
        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal);
1387
        return isolate()->builtins()->LoadIC_Normal();
1388
      }
1389 1390

      // -------------- Fields --------------
1391
      if (lookup->property_details().location() == kField) {
1392
        FieldIndex field = lookup->GetFieldIndex();
1393
        Handle<Object> smi_handler = SimpleFieldLoad(isolate(), field);
1394
        if (receiver_is_holder) {
1395
          return smi_handler;
1396
        }
1397 1398
        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
        return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1399
      }
1400

1401
      // -------------- Constant properties --------------
1402
      DCHECK_EQ(kDescriptor, lookup->property_details().location());
1403 1404 1405 1406 1407
      Handle<Object> smi_handler =
          LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
      if (receiver_is_holder) {
        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
        return smi_handler;
1408
      }
1409 1410
      TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
      return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
    }

    case LookupIterator::INTEGER_INDEXED_EXOTIC:
      TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
      return slow_stub();
    case LookupIterator::ACCESS_CHECK:
    case LookupIterator::JSPROXY:
    case LookupIterator::NOT_FOUND:
    case LookupIterator::TRANSITION:
      UNREACHABLE();
  }

  return Handle<Code>::null();
}

1426 1427 1428
Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
                                      Handle<Object> unused,
                                      CacheHolderFlag cache_holder) {
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
#ifdef DEBUG
  // Only used by DCHECKs below.
  Handle<Object> receiver = lookup->GetReceiver();
  bool receiver_is_holder = receiver.is_identical_to(holder);
#endif
  // Non-map-specific handler stubs have already been selected.
  DCHECK(!receiver->IsString() ||
         !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
  DCHECK(!receiver->IsStringWrapper() ||
         !Name::Equals(isolate()->factory()->length_string(), lookup->name()));

  DCHECK(!(
      receiver->IsJSFunction() &&
      Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
      receiver->IsConstructor() &&
      !Handle<JSFunction>::cast(receiver)
           ->map()
           ->has_non_instance_prototype()));

  Handle<Map> map = receiver_map();
  switch (lookup->state()) {
    case LookupIterator::INTERCEPTOR: {
1452
      DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
      TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
      NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
      // Perform a lookup behind the interceptor. Copy the LookupIterator since
      // the original iterator will be used to fetch the value.
      LookupIterator it = *lookup;
      it.Next();
      LookupForRead(&it);
      return compiler.CompileLoadInterceptor(&it);
    }

    case LookupIterator::ACCESSOR: {
#ifdef DEBUG
      int object_offset;
      DCHECK(!Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
                                                 &object_offset));
#endif

      DCHECK(IsCompatibleReceiver(lookup, map));
      Handle<Object> accessors = lookup->GetAccessors();
      if (accessors->IsAccessorPair()) {
1473 1474 1475 1476
        if (lookup->TryLookupCachedProperty()) {
          DCHECK_EQ(LookupIterator::DATA, lookup->state());
          return ComputeHandler(lookup);
        }
1477
        DCHECK(holder->HasFastProperties());
1478
        DCHECK(!GetHostFunction()->shared()->HasDebugInfo());
1479 1480 1481 1482 1483 1484 1485
        Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
                              isolate());
        CallOptimization call_optimization(getter);
        NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
        if (call_optimization.is_simple_api_call()) {
          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
          int index = lookup->GetAccessorIndex();
1486
          Handle<Code> code = compiler.CompileLoadCallback(
1487
              lookup->name(), call_optimization, index, slow_stub());
1488
          return code;
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
        }
        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
        int expected_arguments = Handle<JSFunction>::cast(getter)
                                     ->shared()
                                     ->internal_formal_parameter_count();
        return compiler.CompileLoadViaGetter(
            lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
      } else {
        DCHECK(accessors->IsAccessorInfo());
        Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
        DCHECK(v8::ToCData<Address>(info->getter()) != nullptr);
        DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
        DCHECK(holder->HasFastProperties());
        DCHECK(!receiver_is_holder);
        DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
        NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1506 1507
        Handle<Code> code =
            compiler.CompileLoadCallback(lookup->name(), info, slow_stub());
1508
        return code;
1509 1510 1511 1512 1513
      }
      UNREACHABLE();
    }

    case LookupIterator::DATA: {
1514
      DCHECK(lookup->is_dictionary_holder());
1515
      DCHECK(IsLoadIC() || IsLoadGlobalIC());
1516 1517
      DCHECK(holder->IsJSGlobalObject());
      TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
1518
      NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1519 1520 1521 1522
      Handle<PropertyCell> cell = lookup->GetPropertyCell();
      Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(),
                                                     lookup->IsConfigurable());
      return code;
1523
    }
1524

1525
    case LookupIterator::INTEGER_INDEXED_EXOTIC:
1526 1527 1528 1529 1530
    case LookupIterator::ACCESS_CHECK:
    case LookupIterator::JSPROXY:
    case LookupIterator::NOT_FOUND:
    case LookupIterator::TRANSITION:
      UNREACHABLE();
1531
  }
1532
  UNREACHABLE();
1533
  return slow_stub();
1534 1535 1536
}


1537 1538 1539 1540 1541
static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
  // This helper implements a few common fast cases for converting
  // non-smi keys of keyed loads/stores to a smi or a string.
  if (key->IsHeapNumber()) {
    double value = Handle<HeapNumber>::cast(key)->value();
1542
    if (std::isnan(value)) {
1543
      key = isolate->factory()->nan_string();
1544 1545 1546
    } else {
      int int_value = FastD2I(value);
      if (value == int_value && Smi::IsValid(int_value)) {
1547
        key = handle(Smi::FromInt(int_value), isolate);
1548 1549
      }
    }
1550
  } else if (key->IsUndefined(isolate)) {
1551
    key = isolate->factory()->undefined_string();
1552 1553
  } else if (key->IsString()) {
    key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
1554 1555 1556 1557
  }
  return key;
}

1558
void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
1559
  Handle<Map> receiver_map(receiver->map(), isolate());
1560 1561
  DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE &&
         receiver_map->instance_type() != JS_PROXY_TYPE);  // Checked by caller.
1562
  MapHandleList target_receiver_maps;
1563 1564
  TargetMaps(&target_receiver_maps);

1565
  if (target_receiver_maps.length() == 0) {
1566
    Handle<Object> handler =
1567
        ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
1568
    return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1569 1570
  }

1571
  for (int i = 0; i < target_receiver_maps.length(); i++) {
1572 1573 1574
    Handle<Map> map = target_receiver_maps.at(i);
    if (map.is_null()) continue;
    if (map->instance_type() == JS_VALUE_TYPE) {
1575
      TRACE_GENERIC_IC("JSValue");
1576
      return;
1577
    }
1578
    if (map->instance_type() == JS_PROXY_TYPE) {
1579
      TRACE_GENERIC_IC("JSProxy");
1580 1581
      return;
    }
1582 1583
  }

1584 1585 1586 1587 1588 1589 1590
  // The first time a receiver is seen that is a transitioned version of the
  // previous monomorphic receiver type, assume the new ElementsKind is the
  // monomorphic type. This benefits global arrays that only transition
  // once, and all call sites accessing them are faster if they remain
  // monomorphic. If this optimistic assumption is not true, the IC will
  // miss again and it will become polymorphic and support both the
  // untransitioned and transitioned maps.
1591 1592 1593 1594
  if (state() == MONOMORPHIC && !receiver->IsString() &&
      IsMoreGeneralElementsKindTransition(
          target_receiver_maps.at(0)->elements_kind(),
          Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1595
    Handle<Object> handler =
1596
        ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
1597
    return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1598 1599
  }

1600
  DCHECK(state() != GENERIC);
1601 1602 1603 1604 1605 1606

  // Determine the list of receiver maps that this call site has seen,
  // adding the map that was just encountered.
  if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
    // If the miss wasn't due to an unseen map, a polymorphic stub
    // won't help, use the generic stub.
1607
    TRACE_GENERIC_IC("same map added twice");
1608
    return;
1609 1610 1611 1612 1613
  }

  // If the maximum number of receiver maps has been exceeded, use the generic
  // version of the IC.
  if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1614
    TRACE_GENERIC_IC("max polymorph exceeded");
1615
    return;
1616 1617
  }

1618
  List<Handle<Object>> handlers(target_receiver_maps.length());
1619
  ElementHandlerCompiler compiler(isolate());
1620
  compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
1621
  ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
1622 1623 1624
}


1625 1626
MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
                                      Handle<Object> key) {
1627
  if (MigrateDeprecated(object)) {
1628
    Handle<Object> result;
1629
    ASSIGN_RETURN_ON_EXCEPTION(
1630
        isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1631 1632
        Object);
    return result;
1633 1634
  }

1635
  Handle<Object> load_handle;
1636

1637 1638
  // Check for non-string values that can be converted into an
  // internalized string directly or is representable as a smi.
1639
  key = TryConvertKey(key, isolate());
1640

1641 1642 1643 1644
  uint32_t index;
  if ((key->IsInternalizedString() &&
       !String::cast(*key)->AsArrayIndex(&index)) ||
      key->IsSymbol()) {
1645 1646 1647
    ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
                               LoadIC::Load(object, Handle<Name>::cast(key)),
                               Object);
1648 1649
  } else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
             !object->IsJSValue()) {
1650 1651 1652
    if ((object->IsJSObject() && key->IsSmi()) ||
        (object->IsString() && key->IsNumber())) {
      UpdateLoadElement(Handle<HeapObject>::cast(object));
1653 1654 1655
      if (is_vector_set()) {
        TRACE_IC("LoadIC", key);
      }
1656
    }
1657
  }
1658

verwaest's avatar
verwaest committed
1659
  if (!is_vector_set()) {
1660
    ConfigureVectorState(MEGAMORPHIC, key);
1661
    TRACE_IC("LoadIC", key);
danno@chromium.org's avatar
danno@chromium.org committed
1662
  }
1663

1664
  if (!load_handle.is_null()) return load_handle;
1665

1666
  Handle<Object> result;
1667 1668 1669
  ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
                             Runtime::GetObjectProperty(isolate(), object, key),
                             Object);
1670
  return result;
1671 1672 1673
}


1674 1675
bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
                             JSReceiver::StoreFromKeyed store_mode) {
1676
  // Disable ICs for non-JSObjects for now.
1677 1678 1679 1680
  Handle<Object> object = it->GetReceiver();
  if (!object->IsJSObject()) return false;
  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
  DCHECK(!receiver->map()->is_deprecated());
1681

1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692
  for (; it->IsFound(); it->Next()) {
    switch (it->state()) {
      case LookupIterator::NOT_FOUND:
      case LookupIterator::TRANSITION:
        UNREACHABLE();
      case LookupIterator::JSPROXY:
        return false;
      case LookupIterator::INTERCEPTOR: {
        Handle<JSObject> holder = it->GetHolder<JSObject>();
        InterceptorInfo* info = holder->GetNamedInterceptor();
        if (it->HolderIsReceiverOrHiddenPrototype()) {
1693
          return !info->non_masking() && receiver.is_identical_to(holder) &&
1694 1695 1696
                 !info->setter()->IsUndefined(it->isolate());
        } else if (!info->getter()->IsUndefined(it->isolate()) ||
                   !info->query()->IsUndefined(it->isolate())) {
1697 1698 1699 1700 1701 1702 1703
          return false;
        }
        break;
      }
      case LookupIterator::ACCESS_CHECK:
        if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
        break;
1704 1705
      case LookupIterator::ACCESSOR:
        return !it->IsReadOnly();
1706 1707
      case LookupIterator::INTEGER_INDEXED_EXOTIC:
        return false;
1708
      case LookupIterator::DATA: {
1709
        if (it->IsReadOnly()) return false;
1710 1711
        Handle<JSObject> holder = it->GetHolder<JSObject>();
        if (receiver.is_identical_to(holder)) {
1712 1713 1714
          it->PrepareForDataProperty(value);
          // The previous receiver map might just have been deprecated,
          // so reload it.
1715
          update_receiver_map(receiver);
1716 1717 1718 1719 1720
          return true;
        }

        // Receiver != holder.
        if (receiver->IsJSGlobalProxy()) {
1721
          PrototypeIterator iter(it->isolate(), receiver);
1722 1723 1724
          return it->GetHolder<Object>().is_identical_to(
              PrototypeIterator::GetCurrent(iter));
        }
antonm@chromium.org's avatar
antonm@chromium.org committed
1725

1726 1727
        if (it->HolderIsReceiverOrHiddenPrototype()) return false;

1728 1729
        if (it->ExtendingNonExtensible(receiver)) return false;
        it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1730
        return it->IsCacheableTransition();
1731
      }
1732
    }
1733
  }
1734

1735 1736 1737
  receiver = it->GetStoreTarget();
  if (it->ExtendingNonExtensible(receiver)) return false;
  it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1738
  return it->IsCacheableTransition();
antonm@chromium.org's avatar
antonm@chromium.org committed
1739 1740 1741
}


1742
MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1743 1744
                                   Handle<Object> value,
                                   JSReceiver::StoreFromKeyed store_mode) {
1745
  if (object->IsJSGlobalObject() && name->IsString()) {
1746
    // Look up in script context table.
1747
    Handle<String> str_name = Handle<String>::cast(name);
1748
    Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
1749 1750
    Handle<ScriptContextTable> script_contexts(
        global->native_context()->script_context_table());
1751

1752 1753 1754 1755
    ScriptContextTable::LookupResult lookup_result;
    if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
      Handle<Context> script_context = ScriptContextTable::GetContext(
          script_contexts, lookup_result.context_index);
1756
      if (lookup_result.mode == CONST) {
1757
        return TypeError(MessageTemplate::kConstAssign, object, name);
1758
      }
1759

1760
      Handle<Object> previous_value =
1761
          FixedArray::get(*script_context, lookup_result.slot_index, isolate());
1762

1763
      if (previous_value->IsTheHole(isolate())) {
1764 1765
        // Do not install stubs and stay pre-monomorphic for
        // uninitialized accesses.
1766
        return ReferenceError(name);
1767 1768
      }

1769
      if (FLAG_use_ic &&
1770
          StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1771
        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
1772
        StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1773 1774 1775
        PatchCache(name, stub.GetCode());
      }

1776
      script_context->set(lookup_result.slot_index, *value);
1777 1778 1779 1780
      return value;
    }
  }

1781 1782
  // TODO(verwaest): Let SetProperty do the migration, since storing a property
  // might deprecate the current map again, if value does not fit.
1783
  if (MigrateDeprecated(object) || object->IsJSProxy()) {
1784
    Handle<Object> result;
1785
    ASSIGN_RETURN_ON_EXCEPTION(
1786
        isolate(), result,
1787
        Object::SetProperty(object, name, value, language_mode()), Object);
1788
    return result;
1789
  }
1790

1791 1792
  // If the object is undefined or null it's illegal to try to set any
  // properties on it; throw a TypeError in that case.
1793
  if (object->IsNullOrUndefined(isolate())) {
1794 1795 1796 1797 1798 1799 1800
    if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) {
      // Ensure the IC state progresses.
      TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
      update_receiver_map(object);
      PatchCache(name, slow_stub());
      TRACE_IC("StoreIC", name);
    }
1801
    return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1802
  }
1803

1804 1805 1806
  if (state() != UNINITIALIZED) {
    JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
  }
1807 1808
  LookupIterator it(object, name);
  if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1809

1810 1811 1812
  MAYBE_RETURN_NULL(
      Object::SetProperty(&it, value, language_mode(), store_mode));
  return value;
1813 1814
}

1815 1816 1817 1818 1819
void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
                           JSReceiver::StoreFromKeyed store_mode) {
  if (state() == UNINITIALIZED) {
    // This is the first time we execute this inline cache. Set the target to
    // the pre monomorphic stub to delay setting the monomorphic state.
1820
    TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1821
    ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
1822 1823 1824
    TRACE_IC("StoreIC", lookup->name());
    return;
  }
1825

1826 1827 1828 1829 1830 1831
  Handle<Object> handler;
  if (LookupForWrite(lookup, value, store_mode)) {
    handler = ComputeHandler(lookup, value);
  } else {
    TRACE_GENERIC_IC("LookupForWrite said 'false'");
    handler = slow_stub();
1832
  }
1833

1834
  PatchCache(lookup->name(), handler);
1835
  TRACE_IC("StoreIC", lookup->name());
1836 1837
}

1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
                                        Handle<JSObject> holder,
                                        Handle<Map> transition,
                                        Handle<Name> name) {
  int descriptor = transition->LastAdded();
  Handle<DescriptorArray> descriptors(transition->instance_descriptors());
  PropertyDetails details = descriptors->GetDetails(descriptor);
  Representation representation = details.representation();
  DCHECK(!representation.IsNone());

  // Declarative handlers don't support access checks.
  DCHECK(!transition->is_access_check_needed());

  Handle<Object> smi_handler;
1852 1853
  DCHECK_EQ(kData, details.kind());
  if (details.location() == kDescriptor) {
1854 1855 1856
    smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);

  } else {
1857
    DCHECK_EQ(kField, details.location());
1858 1859 1860 1861 1862 1863 1864
    bool extend_storage =
        Map::cast(transition->GetBackPointer())->unused_property_fields() == 0;

    FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
    smi_handler = StoreHandler::TransitionToField(
        isolate(), descriptor, index, representation, extend_storage);
  }
1865 1866 1867 1868 1869
  // |holder| is either a receiver if the property is non-existent or
  // one of the prototypes.
  DCHECK(!holder.is_null());
  bool is_nonexistent = holder->map() == transition->GetBackPointer();
  if (is_nonexistent) holder = Handle<JSObject>::null();
1870

1871 1872
  int checks_count =
      GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893
  DCHECK_LE(0, checks_count);
  DCHECK(!receiver_map->IsJSGlobalObjectMap());

  Handle<Object> validity_cell =
      Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
  if (validity_cell.is_null()) {
    DCHECK_EQ(0, checks_count);
    validity_cell = handle(Smi::FromInt(0), isolate());
  }

  Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);

  Factory* factory = isolate()->factory();
  if (checks_count == 0) {
    return factory->NewTuple3(transition_cell, smi_handler, validity_cell);
  }
  Handle<FixedArray> handler_array(factory->NewFixedArray(
      StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
  handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
  handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
  handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell);
1894
  InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
1895 1896 1897
                      StoreHandler::kFirstPrototypeIndex);
  return handler_array;
}
1898

1899
static Handle<Code> PropertyCellStoreHandler(
1900
    Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder,
1901
    Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1902 1903 1904 1905 1906
  auto constant_type = Nothing<PropertyCellConstantType>();
  if (type == PropertyCellType::kConstantType) {
    constant_type = Just(cell->GetConstantType());
  }
  StoreGlobalStub stub(isolate, type, constant_type,
1907 1908 1909 1910 1911 1912 1913
                       receiver->IsJSGlobalProxy());
  auto code = stub.GetCodeCopyFromTemplate(holder, cell);
  // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
  HeapObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}

1914
Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
1915 1916
  DCHECK_NE(LookupIterator::JSPROXY, lookup->state());

1917
  // This is currently guaranteed by checks in StoreIC::Store.
1918 1919
  Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1920
  DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1921

1922 1923
  switch (lookup->state()) {
    case LookupIterator::TRANSITION: {
1924
      auto store_target = lookup->GetStoreTarget();
1925
      if (store_target->IsJSGlobalObject()) {
1926
        break;  // Custom-compiled handler.
1927
      }
1928
      // Currently not handled by CompileStoreTransition.
1929
      if (!holder->HasFastProperties()) {
1930
        TRACE_GENERIC_IC("transition from slow");
1931 1932
        TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
        return slow_stub();
1933
      }
1934
      DCHECK(lookup->IsCacheableTransition());
1935 1936 1937 1938
      Handle<Map> transition = lookup->transition_map();
      TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
      return StoreTransition(receiver_map(), holder, transition,
                             lookup->name());
1939
    }
1940

1941
    case LookupIterator::INTERCEPTOR: {
1942
      DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1943
      TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1944 1945
      StoreInterceptorStub stub(isolate());
      return stub.GetCode();
1946 1947
    }

1948
    case LookupIterator::ACCESSOR: {
1949
      if (!holder->HasFastProperties()) {
1950
        TRACE_GENERIC_IC("accessor on slow map");
1951 1952
        TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
        return slow_stub();
1953
      }
1954
      Handle<Object> accessors = lookup->GetAccessors();
1955 1956
      if (accessors->IsAccessorInfo()) {
        Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1957
        if (v8::ToCData<Address>(info->setter()) == nullptr) {
1958
          TRACE_GENERIC_IC("setter == nullptr");
1959 1960
          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
          return slow_stub();
1961
        }
1962 1963
        if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
            !lookup->HolderIsReceiverOrHiddenPrototype()) {
1964
          TRACE_GENERIC_IC("special data property in prototype chain");
1965 1966
          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
          return slow_stub();
1967
        }
1968 1969
        if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
                                                   receiver_map())) {
1970
          TRACE_GENERIC_IC("incompatible receiver type");
1971 1972
          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
          return slow_stub();
1973
        }
1974 1975 1976 1977 1978
        if (info->is_sloppy() && !receiver->IsJSReceiver()) {
          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
          return slow_stub();
        }
        break;  // Custom-compiled handler.
1979 1980 1981
      } else if (accessors->IsAccessorPair()) {
        Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
                              isolate());
1982
        if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
1983
          TRACE_GENERIC_IC("setter not a function");
1984 1985
          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
          return slow_stub();
1986
        }
1987 1988 1989
        CallOptimization call_optimization(setter);
        if (call_optimization.is_simple_api_call()) {
          if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1990
            break;  // Custom-compiled handler.
1991
          }
1992
          TRACE_GENERIC_IC("incompatible receiver");
1993 1994
          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
          return slow_stub();
1995
        }
1996
        break;  // Custom-compiled handler.
1997
      }
1998 1999
      TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
      return slow_stub();
2000
    }
2001 2002

    case LookupIterator::DATA: {
2003
      DCHECK_EQ(kData, lookup->property_details().kind());
2004
      if (lookup->is_dictionary_holder()) {
2005
        if (holder->IsJSGlobalObject()) {
2006
          break;  // Custom-compiled handler.
2007
        }
2008
        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal);
2009 2010 2011 2012 2013
        DCHECK(holder.is_identical_to(receiver));
        return isolate()->builtins()->StoreIC_Normal();
      }

      // -------------- Fields --------------
2014
      if (lookup->property_details().location() == kField) {
2015 2016 2017 2018
        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
        int descriptor = lookup->GetFieldDescriptorIndex();
        FieldIndex index = lookup->GetFieldIndex();
        return StoreHandler::StoreField(isolate(), descriptor, index,
2019
                                        lookup->constness(),
2020
                                        lookup->representation());
2021 2022 2023
      }

      // -------------- Constant properties --------------
2024
      DCHECK_EQ(kDescriptor, lookup->property_details().location());
2025
      TRACE_GENERIC_IC("constant property");
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038
      TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
      return slow_stub();
    }

    case LookupIterator::INTEGER_INDEXED_EXOTIC:
    case LookupIterator::ACCESS_CHECK:
    case LookupIterator::JSPROXY:
    case LookupIterator::NOT_FOUND:
      UNREACHABLE();
  }
  return Handle<Code>::null();
}

2039 2040 2041
Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
                                       Handle<Object> value,
                                       CacheHolderFlag cache_holder) {
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
  DCHECK_NE(LookupIterator::JSPROXY, lookup->state());

  // This is currently guaranteed by checks in StoreIC::Store.
  Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
  DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());

  switch (lookup->state()) {
    case LookupIterator::TRANSITION: {
      auto store_target = lookup->GetStoreTarget();
      if (store_target->IsJSGlobalObject()) {
        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
2054
        Handle<PropertyCell> cell = lookup->transition_cell();
2055
        cell->set_value(*value);
2056
        Handle<Code> code = PropertyCellStoreHandler(
2057 2058 2059 2060 2061
            isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
            lookup->name(), cell, PropertyCellType::kConstant);
        cell->set_value(isolate()->heap()->the_hole_value());
        return code;
      }
2062
      UNREACHABLE();
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080
    }

    case LookupIterator::INTERCEPTOR:
      UNREACHABLE();

    case LookupIterator::ACCESSOR: {
      DCHECK(holder->HasFastProperties());
      Handle<Object> accessors = lookup->GetAccessors();
      if (accessors->IsAccessorInfo()) {
        Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
        DCHECK(v8::ToCData<Address>(info->setter()) != 0);
        DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
               lookup->HolderIsReceiverOrHiddenPrototype());
        DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
                                                     receiver_map()));
        DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
        NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
2081 2082 2083 2084 2085
        // TODO(ishell): don't hard-code language mode into the handler because
        // this handler can be re-used through megamorphic stub cache for wrong
        // language mode.
        // Better pass vector/slot to Runtime::kStoreCallbackProperty and
        // let it decode the language mode from the IC kind.
2086 2087 2088
        Handle<Code> code = compiler.CompileStoreCallback(
            receiver, lookup->name(), info, language_mode());
        return code;
2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
      } else {
        DCHECK(accessors->IsAccessorPair());
        Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
                              isolate());
        DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo());
        CallOptimization call_optimization(setter);
        NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
        if (call_optimization.is_simple_api_call()) {
          DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder));
          TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
2099 2100
          Handle<Code> code = compiler.CompileStoreCallback(
              receiver, lookup->name(), call_optimization,
2101
              lookup->GetAccessorIndex(), slow_stub());
2102
          return code;
2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
        }
        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
        int expected_arguments = JSFunction::cast(*setter)
                                     ->shared()
                                     ->internal_formal_parameter_count();
        return compiler.CompileStoreViaSetter(receiver, lookup->name(),
                                              lookup->GetAccessorIndex(),
                                              expected_arguments);
      }
    }

    case LookupIterator::DATA: {
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
      DCHECK(lookup->is_dictionary_holder());
      DCHECK(holder->IsJSGlobalObject());
      TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
      DCHECK(holder.is_identical_to(receiver) ||
             receiver->map()->prototype() == *holder);
      auto cell = lookup->GetPropertyCell();
      auto updated_type =
          PropertyCell::UpdatedType(cell, value, lookup->property_details());
      auto code = PropertyCellStoreHandler(isolate(), receiver,
                                           Handle<JSGlobalObject>::cast(holder),
                                           lookup->name(), cell, updated_type);
      return code;
2127 2128
    }

2129
    case LookupIterator::INTEGER_INDEXED_EXOTIC:
2130 2131 2132 2133 2134
    case LookupIterator::ACCESS_CHECK:
    case LookupIterator::JSPROXY:
    case LookupIterator::NOT_FOUND:
      UNREACHABLE();
  }
2135
  UNREACHABLE();
2136
  return slow_stub();
2137 2138
}

2139 2140
void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
                                      KeyedAccessStoreMode store_mode) {
2141 2142 2143
  MapHandleList target_receiver_maps;
  TargetMaps(&target_receiver_maps);
  if (target_receiver_maps.length() == 0) {
2144 2145
    Handle<Map> monomorphic_map =
        ComputeTransitionedMap(receiver_map, store_mode);
2146
    store_mode = GetNonTransitioningStoreMode(store_mode);
2147
    Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
2148
    return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
2149 2150
  }

2151 2152 2153
  for (int i = 0; i < target_receiver_maps.length(); i++) {
    if (!target_receiver_maps.at(i).is_null() &&
        target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
2154
      TRACE_GENERIC_IC("JSValue");
2155 2156 2157 2158
      return;
    }
  }

2159 2160 2161 2162
  // There are several special cases where an IC that is MONOMORPHIC can still
  // transition to a different GetNonTransitioningStoreMode IC that handles a
  // superset of the original IC. Handle those here if the receiver map hasn't
  // changed or it has transitioned to a more general kind.
2163
  KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
2164
  Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
2165
  if (state() == MONOMORPHIC) {
2166
    Handle<Map> transitioned_receiver_map = receiver_map;
2167
    if (IsTransitionStoreMode(store_mode)) {
2168 2169
      transitioned_receiver_map =
          ComputeTransitionedMap(receiver_map, store_mode);
2170
    }
2171 2172
    if ((receiver_map.is_identical_to(previous_receiver_map) &&
         IsTransitionStoreMode(store_mode)) ||
2173 2174
        IsTransitionOfMonomorphicTarget(*previous_receiver_map,
                                        *transitioned_receiver_map)) {
2175 2176 2177
      // If the "old" and "new" maps are in the same elements map family, or
      // if they at least come from the same origin for a transitioning store,
      // stay MONOMORPHIC and use the map for the most generic ElementsKind.
2178
      store_mode = GetNonTransitioningStoreMode(store_mode);
2179
      Handle<Object> handler =
2180
          StoreElementHandler(transitioned_receiver_map, store_mode);
2181 2182 2183 2184 2185 2186 2187 2188
      ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
      return;
    }
    if (receiver_map.is_identical_to(previous_receiver_map) &&
        old_store_mode == STANDARD_STORE &&
        (store_mode == STORE_AND_GROW_NO_TRANSITION ||
         store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
         store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
2189 2190 2191
      // A "normal" IC that handles stores can switch to a version that can
      // grow at the end of the array, handle OOB accesses or copy COW arrays
      // and still stay MONOMORPHIC.
2192
      Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
2193
      return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
2194
    }
2195 2196
  }

2197
  DCHECK(state() != GENERIC);
danno@chromium.org's avatar
danno@chromium.org committed
2198

2199
  bool map_added =
2200
      AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
2201

2202 2203
  if (IsTransitionStoreMode(store_mode)) {
    Handle<Map> transitioned_receiver_map =
2204
        ComputeTransitionedMap(receiver_map, store_mode);
2205 2206
    map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
                                            transitioned_receiver_map);
2207
  }
2208

2209 2210
  if (!map_added) {
    // If the miss wasn't due to an unseen map, a polymorphic stub
2211
    // won't help, use the megamorphic stub which can handle everything.
2212
    TRACE_GENERIC_IC("same map added twice");
2213
    return;
danno@chromium.org's avatar
danno@chromium.org committed
2214 2215
  }

2216 2217
  // If the maximum number of receiver maps has been exceeded, use the
  // megamorphic version of the IC.
2218
  if (target_receiver_maps.length() > kMaxKeyedPolymorphism) return;
danno@chromium.org's avatar
danno@chromium.org committed
2219

2220
  // Make sure all polymorphic handlers have the same store mode, otherwise the
2221
  // megamorphic stub must be used.
2222 2223 2224 2225 2226
  store_mode = GetNonTransitioningStoreMode(store_mode);
  if (old_store_mode != STANDARD_STORE) {
    if (store_mode == STANDARD_STORE) {
      store_mode = old_store_mode;
    } else if (store_mode != old_store_mode) {
2227
      TRACE_GENERIC_IC("store mode mismatch");
2228
      return;
2229
    }
2230 2231
  }

2232 2233
  // If the store mode isn't the standard mode, make sure that all polymorphic
  // receivers are either external arrays, or all "normal" arrays. Otherwise,
2234
  // use the megamorphic stub.
2235 2236 2237
  if (store_mode != STANDARD_STORE) {
    int external_arrays = 0;
    for (int i = 0; i < target_receiver_maps.length(); ++i) {
2238
      if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
2239 2240 2241 2242 2243
        external_arrays++;
      }
    }
    if (external_arrays != 0 &&
        external_arrays != target_receiver_maps.length()) {
2244
      TRACE_GENERIC_IC("unsupported combination of external and normal arrays");
2245
      return;
2246 2247 2248
    }
  }

2249
  MapHandleList transitioned_maps(target_receiver_maps.length());
2250
  List<Handle<Object>> handlers(target_receiver_maps.length());
2251 2252
  StoreElementPolymorphicHandlers(&target_receiver_maps, &transitioned_maps,
                                  &handlers, store_mode);
2253
  ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
danno@chromium.org's avatar
danno@chromium.org committed
2254 2255 2256
}


2257
Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
2258
    Handle<Map> map, KeyedAccessStoreMode store_mode) {
2259
  switch (store_mode) {
2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
    case STORE_TRANSITION_TO_OBJECT:
    case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
      ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
                              ? FAST_HOLEY_ELEMENTS
                              : FAST_ELEMENTS;
      return Map::TransitionElementsTo(map, kind);
    }
    case STORE_TRANSITION_TO_DOUBLE:
    case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
      ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
                              ? FAST_HOLEY_DOUBLE_ELEMENTS
                              : FAST_DOUBLE_ELEMENTS;
      return Map::TransitionElementsTo(map, kind);
    }
2274
    case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
2275
      DCHECK(map->has_fixed_typed_array_elements());
2276
    // Fall through
2277 2278
    case STORE_NO_TRANSITION_HANDLE_COW:
    case STANDARD_STORE:
2279
    case STORE_AND_GROW_NO_TRANSITION:
2280
      return map;
2281
  }
2282 2283
  UNREACHABLE();
  return MaybeHandle<Map>().ToHandleChecked();
2284 2285
}

2286 2287 2288 2289 2290 2291
Handle<Object> KeyedStoreIC::StoreElementHandler(
    Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
  DCHECK(store_mode == STANDARD_STORE ||
         store_mode == STORE_AND_GROW_NO_TRANSITION ||
         store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
         store_mode == STORE_NO_TRANSITION_HANDLE_COW);
2292
  DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly());
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331

  ElementsKind elements_kind = receiver_map->elements_kind();
  bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
  Handle<Code> stub;
  if (receiver_map->has_sloppy_arguments_elements()) {
    TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
    stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
  } else if (receiver_map->has_fast_elements() ||
             receiver_map->has_fixed_typed_array_elements()) {
    TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
    stub =
        StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode)
            .GetCode();
  } else {
    TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
    DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
    stub = StoreSlowElementStub(isolate(), store_mode).GetCode();
  }
  Handle<Object> validity_cell =
      Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
  if (validity_cell.is_null()) {
    return stub;
  }
  return isolate()->factory()->NewTuple2(validity_cell, stub);
}

void KeyedStoreIC::StoreElementPolymorphicHandlers(
    MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
    List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) {
  DCHECK(store_mode == STANDARD_STORE ||
         store_mode == STORE_AND_GROW_NO_TRANSITION ||
         store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
         store_mode == STORE_NO_TRANSITION_HANDLE_COW);

  for (int i = 0; i < receiver_maps->length(); ++i) {
    Handle<Map> receiver_map(receiver_maps->at(i));
    Handle<Object> handler;
    Handle<Map> transitioned_map;

2332 2333
    if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
        receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2334 2335 2336 2337
      // TODO(mvstanton): Consider embedding store_mode in the state of the slow
      // keyed store ic for uniformity.
      TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
      handler = isolate()->builtins()->KeyedStoreIC_Slow();
2338

2339
    } else {
2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370
      {
        Map* tmap =
            receiver_map->FindElementsKindTransitionedMap(receiver_maps);
        if (tmap != nullptr) transitioned_map = handle(tmap);
      }

      // TODO(mvstanton): The code below is doing pessimistic elements
      // transitions. I would like to stop doing that and rely on Allocation
      // Site Tracking to do a better job of ensuring the data types are what
      // they need to be. Not all the elements are in place yet, pessimistic
      // elements transitions are still important for performance.
      if (!transitioned_map.is_null()) {
        bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
        ElementsKind elements_kind = receiver_map->elements_kind();
        TRACE_HANDLER_STATS(isolate(),
                            KeyedStoreIC_ElementsTransitionAndStoreStub);
        Handle<Code> stub =
            ElementsTransitionAndStoreStub(isolate(), elements_kind,
                                           transitioned_map->elements_kind(),
                                           is_js_array, store_mode)
                .GetCode();
        Handle<Object> validity_cell =
            Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
        if (validity_cell.is_null()) {
          handler = stub;
        } else {
          handler = isolate()->factory()->NewTuple2(validity_cell, stub);
        }
      } else {
        handler = StoreElementHandler(receiver_map, store_mode);
      }
2371 2372 2373 2374 2375 2376
    }
    DCHECK(!handler.is_null());
    handlers->Add(handler);
    transitioned_maps->Add(transitioned_map);
  }
}
2377

2378 2379
bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
  uint32_t length = 0;
2380
  if (receiver->IsJSArray()) {
2381 2382 2383
    JSArray::cast(*receiver)->length()->ToArrayLength(&length);
  } else {
    length = static_cast<uint32_t>(receiver->elements()->length());
2384
  }
2385
  return index >= length;
2386 2387 2388
}


2389 2390
static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
                                         uint32_t index, Handle<Object> value) {
2391
  bool oob_access = IsOutOfBoundsAccess(receiver, index);
2392 2393 2394
  // Don't consider this a growing store if the store would send the receiver to
  // dictionary mode.
  bool allow_growth = receiver->IsJSArray() && oob_access &&
2395
                      !receiver->WouldConvertToSlowElements(index);
2396 2397
  if (allow_growth) {
    // Handle growing array in stub if necessary.
2398
    if (receiver->HasFastSmiElements()) {
2399
      if (value->IsHeapNumber()) {
2400
        return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
2401 2402
      }
      if (value->IsHeapObject()) {
2403
        return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2404 2405 2406
      }
    } else if (receiver->HasFastDoubleElements()) {
      if (!value->IsSmi() && !value->IsHeapNumber()) {
2407
        return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2408 2409 2410 2411 2412
      }
    }
    return STORE_AND_GROW_NO_TRANSITION;
  } else {
    // Handle only in-bounds elements accesses.
2413
    if (receiver->HasFastSmiElements()) {
2414
      if (value->IsHeapNumber()) {
2415
        return STORE_TRANSITION_TO_DOUBLE;
2416
      } else if (value->IsHeapObject()) {
2417
        return STORE_TRANSITION_TO_OBJECT;
2418 2419 2420
      }
    } else if (receiver->HasFastDoubleElements()) {
      if (!value->IsSmi() && !value->IsHeapNumber()) {
2421
        return STORE_TRANSITION_TO_OBJECT;
2422 2423
      }
    }
2424
    if (!FLAG_trace_external_array_abuse &&
2425
        receiver->map()->has_fixed_typed_array_elements() && oob_access) {
2426
      return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2427 2428 2429 2430
    }
    Heap* heap = receiver->GetHeap();
    if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
      return STORE_NO_TRANSITION_HANDLE_COW;
2431 2432 2433
    } else {
      return STANDARD_STORE;
    }
2434 2435 2436 2437
  }
}


2438 2439 2440
MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
                                        Handle<Object> key,
                                        Handle<Object> value) {
2441 2442
  // TODO(verwaest): Let SetProperty do the migration, since storing a property
  // might deprecate the current map again, if value does not fit.
2443
  if (MigrateDeprecated(object)) {
2444
    Handle<Object> result;
2445
    ASSIGN_RETURN_ON_EXCEPTION(
2446
        isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2447
                                                      value, language_mode()),
2448 2449
        Object);
    return result;
2450 2451
  }

2452 2453
  // Check for non-string values that can be converted into an
  // internalized string directly or is representable as a smi.
2454 2455
  key = TryConvertKey(key, isolate());

2456
  Handle<Object> store_handle;
2457

2458 2459 2460 2461
  uint32_t index;
  if ((key->IsInternalizedString() &&
       !String::cast(*key)->AsArrayIndex(&index)) ||
      key->IsSymbol()) {
2462
    ASSIGN_RETURN_ON_EXCEPTION(
2463
        isolate(), store_handle,
2464
        StoreIC::Store(object, Handle<Name>::cast(key), value,
2465 2466
                       JSReceiver::MAY_BE_STORE_FROM_KEYED),
        Object);
2467
    if (!is_vector_set()) {
2468
      ConfigureVectorState(MEGAMORPHIC, key);
2469
      TRACE_GENERIC_IC("unhandled internalized string key");
2470
      TRACE_IC("StoreIC", key);
2471
    }
2472 2473
    return store_handle;
  }
2474

2475 2476
  bool use_ic = FLAG_use_ic && !object->IsStringWrapper() &&
                !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy();
2477 2478 2479 2480 2481
  if (use_ic && !object->IsSmi()) {
    // Don't use ICs for maps of the objects in Array's prototype chain. We
    // expect to be able to trap element sets to objects with those maps in
    // the runtime to enable optimization of element hole access.
    Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2482
    if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2483
      TRACE_GENERIC_IC("map in array prototype");
2484 2485
      use_ic = false;
    }
2486
  }
2487

2488
  Handle<Map> old_receiver_map;
2489
  bool is_arguments = false;
2490 2491 2492 2493 2494
  bool key_is_valid_index = false;
  KeyedAccessStoreMode store_mode = STANDARD_STORE;
  if (use_ic && object->IsJSObject()) {
    Handle<JSObject> receiver = Handle<JSObject>::cast(object);
    old_receiver_map = handle(receiver->map(), isolate());
2495 2496
    is_arguments = receiver->IsJSArgumentsObject();
    if (!is_arguments) {
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510
      key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
      if (key_is_valid_index) {
        uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
        store_mode = GetStoreMode(receiver, index, value);
      }
    }
  }

  DCHECK(store_handle.is_null());
  ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
                             Runtime::SetObjectProperty(isolate(), object, key,
                                                        value, language_mode()),
                             Object);

2511
  if (use_ic) {
2512
    if (!old_receiver_map.is_null()) {
2513
      if (is_arguments) {
2514
        TRACE_GENERIC_IC("arguments receiver");
2515
      } else if (key_is_valid_index) {
2516 2517 2518 2519
        // We should go generic if receiver isn't a dictionary, but our
        // prototype chain does have dictionary elements. This ensures that
        // other non-dictionary receivers in the polymorphic case benefit
        // from fast path keyed stores.
2520
        if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2521
          UpdateStoreElement(old_receiver_map, store_mode);
2522
        } else {
2523
          TRACE_GENERIC_IC("dictionary or proxy prototype");
2524
        }
2525
      } else {
2526
        TRACE_GENERIC_IC("non-smi-like key");
2527
      }
2528
    } else {
2529
      TRACE_GENERIC_IC("non-JSObject receiver");
2530 2531 2532
    }
  }

verwaest's avatar
verwaest committed
2533
  if (!is_vector_set()) {
2534
    ConfigureVectorState(MEGAMORPHIC, key);
2535
  }
2536
  TRACE_IC("StoreIC", key);
2537

2538
  return store_handle;
2539 2540 2541
}


2542 2543 2544
#undef TRACE_IC


2545 2546 2547 2548
// ----------------------------------------------------------------------------
// Static IC stub generators.
//

2549
// Used from ic-<arch>.cc.
2550
RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2551
  HandleScope scope(isolate);
2552
  DCHECK_EQ(4, args.length());
2553
  // Runtime functions don't follow the IC's calling convention.
2554
  Handle<Object> receiver = args.at(0);
2555
  Handle<Name> key = args.at<Name>(1);
2556
  Handle<Smi> slot = args.at<Smi>(2);
2557
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2558
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2559 2560 2561
  // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
  // LoadIC miss handler if the handler misses. Since the vector Nexus is
  // set up outside the IC, handle that here.
2562
  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2563
  if (IsLoadICKind(kind)) {
2564
    LoadICNexus nexus(vector, vector_slot);
2565
    LoadIC ic(isolate, &nexus);
2566
    ic.UpdateState(receiver, key);
2567
    RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2568

2569
  } else if (IsLoadGlobalICKind(kind)) {
2570 2571
    DCHECK_EQ(*isolate->global_object(), *receiver);
    LoadGlobalICNexus nexus(vector, vector_slot);
2572
    LoadGlobalIC ic(isolate, &nexus);
2573 2574 2575
    ic.UpdateState(receiver, key);
    RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));

2576
  } else {
2577
    DCHECK(IsKeyedLoadICKind(kind));
2578
    KeyedLoadICNexus nexus(vector, vector_slot);
2579
    KeyedLoadIC ic(isolate, &nexus);
2580
    ic.UpdateState(receiver, key);
2581
    RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2582
  }
2583 2584
}

2585 2586 2587
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
  HandleScope scope(isolate);
2588
  DCHECK_EQ(3, args.length());
2589
  // Runtime functions don't follow the IC's calling convention.
2590
  Handle<JSGlobalObject> global = isolate->global_object();
2591 2592
  Handle<String> name = args.at<String>(0);
  Handle<Smi> slot = args.at<Smi>(1);
2593
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2594
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2595 2596

  LoadGlobalICNexus nexus(vector, vector_slot);
2597
  LoadGlobalIC ic(isolate, &nexus);
2598 2599 2600 2601 2602 2603
  ic.UpdateState(global, name);

  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
  return *result;
}
2604

2605 2606
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
  HandleScope scope(isolate);
2607
  DCHECK_EQ(3, args.length());
2608
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2609

2610
  Handle<Context> native_context = isolate->native_context();
2611
  Handle<ScriptContextTable> script_contexts(
2612
      native_context->script_context_table());
2613 2614 2615 2616 2617 2618 2619

  ScriptContextTable::LookupResult lookup_result;
  if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
    Handle<Context> script_context = ScriptContextTable::GetContext(
        script_contexts, lookup_result.context_index);
    Handle<Object> result =
        FixedArray::get(*script_context, lookup_result.slot_index, isolate);
2620
    if (*result == isolate->heap()->the_hole_value()) {
2621 2622 2623 2624 2625 2626
      THROW_NEW_ERROR_RETURN_FAILURE(
          isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
    }
    return *result;
  }

2627
  Handle<JSGlobalObject> global(native_context->global_object(), isolate);
2628 2629 2630 2631 2632 2633
  Handle<Object> result;
  bool is_found = false;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, result,
      Runtime::GetObjectProperty(isolate, global, name, &is_found));
  if (!is_found) {
2634
    Handle<Smi> slot = args.at<Smi>(1);
2635
    Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2636 2637
    FeedbackSlot vector_slot = vector->ToSlot(slot->value());
    FeedbackSlotKind kind = vector->GetKind(vector_slot);
2638 2639
    // It is actually a LoadGlobalICs here but the predicate handles this case
    // properly.
2640
    if (LoadIC::ShouldThrowReferenceError(kind)) {
2641 2642 2643 2644 2645 2646 2647
      THROW_NEW_ERROR_RETURN_FAILURE(
          isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
    }
  }
  return *result;
}

2648
// Used from ic-<arch>.cc
2649
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2650
  HandleScope scope(isolate);
2651 2652
  DCHECK_EQ(4, args.length());
  // Runtime functions don't follow the IC's calling convention.
2653 2654
  Handle<Object> receiver = args.at(0);
  Handle<Object> key = args.at(1);
2655
  Handle<Smi> slot = args.at<Smi>(2);
2656
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2657
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2658
  KeyedLoadICNexus nexus(vector, vector_slot);
2659
  KeyedLoadIC ic(isolate, &nexus);
2660
  ic.UpdateState(receiver, key);
2661
  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2662 2663
}

2664
// Used from ic-<arch>.cc.
2665
RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2666
  HandleScope scope(isolate);
2667 2668
  DCHECK_EQ(5, args.length());
  // Runtime functions don't follow the IC's calling convention.
2669
  Handle<Object> value = args.at(0);
2670
  Handle<Smi> slot = args.at<Smi>(1);
2671
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2672
  Handle<Object> receiver = args.at(3);
2673
  Handle<Name> key = args.at<Name>(4);
2674
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2675 2676
  FeedbackSlotKind kind = vector->GetKind(vector_slot);
  if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
2677
    StoreICNexus nexus(vector, vector_slot);
2678
    StoreIC ic(isolate, &nexus);
2679
    ic.UpdateState(receiver, key);
2680
    RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2681
  } else {
2682
    DCHECK(IsKeyedStoreICKind(kind));
2683
    KeyedStoreICNexus nexus(vector, vector_slot);
2684
    KeyedStoreIC ic(isolate, &nexus);
2685
    ic.UpdateState(receiver, key);
2686
    RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2687
  }
2688 2689
}

2690
// Used from ic-<arch>.cc.
2691
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2692
  HandleScope scope(isolate);
2693
  DCHECK_EQ(5, args.length());
2694
  // Runtime functions don't follow the IC's calling convention.
2695
  Handle<Object> value = args.at(0);
2696
  Handle<Smi> slot = args.at<Smi>(1);
2697
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2698 2699
  Handle<Object> receiver = args.at(3);
  Handle<Object> key = args.at(4);
2700
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2701
  KeyedStoreICNexus nexus(vector, vector_slot);
2702
  KeyedStoreIC ic(isolate, &nexus);
2703
  ic.UpdateState(receiver, key);
2704
  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2705 2706 2707
}


2708
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2709
  HandleScope scope(isolate);
2710
  DCHECK_EQ(5, args.length());
2711
  // Runtime functions don't follow the IC's calling convention.
2712
  Handle<Object> value = args.at(0);
2713
  Handle<Smi> slot = args.at<Smi>(1);
2714
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2715 2716
  Handle<Object> object = args.at(3);
  Handle<Object> key = args.at(4);
2717
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2718
  LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2719 2720
  RETURN_RESULT_OR_FAILURE(
      isolate,
2721
      Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
danno@chromium.org's avatar
danno@chromium.org committed
2722 2723 2724
}


2725
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2726
  HandleScope scope(isolate);
2727
  DCHECK_EQ(6, args.length());
2728
  // Runtime functions don't follow the IC's calling convention.
2729 2730 2731
  Handle<Object> object = args.at(0);
  Handle<Object> key = args.at(1);
  Handle<Object> value = args.at(2);
2732
  Handle<Map> map = args.at<Map>(3);
2733
  Handle<Smi> slot = args.at<Smi>(4);
2734
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
2735
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2736
  LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2737 2738 2739 2740
  if (object->IsJSObject()) {
    JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
                                     map->elements_kind());
  }
2741 2742
  RETURN_RESULT_OR_FAILURE(
      isolate,
2743
      Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2744 2745 2746
}


2747
MaybeHandle<Object> BinaryOpIC::Transition(
2748
    Handle<AllocationSite> allocation_site, Handle<Object> left,
2749
    Handle<Object> right) {
verwaest's avatar
verwaest committed
2750
  BinaryOpICState state(isolate(), extra_ic_state());
2751 2752

  // Compute the actual result using the builtin for the binary operation.
2753
  Handle<Object> result;
2754 2755 2756 2757
  switch (state.op()) {
    default:
      UNREACHABLE();
    case Token::ADD:
2758 2759
      ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
                                 Object::Add(isolate(), left, right), Object);
2760 2761 2762
      break;
    case Token::SUB:
      ASSIGN_RETURN_ON_EXCEPTION(
2763
          isolate(), result, Object::Subtract(isolate(), left, right), Object);
2764 2765 2766
      break;
    case Token::MUL:
      ASSIGN_RETURN_ON_EXCEPTION(
2767
          isolate(), result, Object::Multiply(isolate(), left, right), Object);
2768 2769 2770
      break;
    case Token::DIV:
      ASSIGN_RETURN_ON_EXCEPTION(
2771
          isolate(), result, Object::Divide(isolate(), left, right), Object);
2772 2773 2774
      break;
    case Token::MOD:
      ASSIGN_RETURN_ON_EXCEPTION(
2775
          isolate(), result, Object::Modulus(isolate(), left, right), Object);
2776 2777 2778
      break;
    case Token::BIT_OR:
      ASSIGN_RETURN_ON_EXCEPTION(
2779
          isolate(), result, Object::BitwiseOr(isolate(), left, right), Object);
2780 2781
      break;
    case Token::BIT_AND:
2782 2783 2784
      ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
                                 Object::BitwiseAnd(isolate(), left, right),
                                 Object);
2785 2786
      break;
    case Token::BIT_XOR:
2787 2788 2789
      ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
                                 Object::BitwiseXor(isolate(), left, right),
                                 Object);
2790 2791
      break;
    case Token::SAR:
2792 2793 2794
      ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
                                 Object::ShiftRight(isolate(), left, right),
                                 Object);
2795 2796 2797
      break;
    case Token::SHR:
      ASSIGN_RETURN_ON_EXCEPTION(
2798
          isolate(), result, Object::ShiftRightLogical(isolate(), left, right),
2799 2800 2801 2802
          Object);
      break;
    case Token::SHL:
      ASSIGN_RETURN_ON_EXCEPTION(
2803
          isolate(), result, Object::ShiftLeft(isolate(), left, right), Object);
2804 2805
      break;
  }
2806

2807 2808 2809 2810 2811 2812 2813
  // Do not try to update the target if the code was marked for lazy
  // deoptimization. (Since we do not relocate addresses in these
  // code objects, an attempt to access the target could fail.)
  if (AddressIsDeoptimizedCode()) {
    return result;
  }

2814
  // Compute the new state.
2815
  BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2816
  state.Update(left, right, result);
2817

2818
  // Check if we have a string operation here.
2819
  Handle<Code> new_target;
2820 2821 2822 2823 2824 2825 2826
  if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
    // Setup the allocation site on-demand.
    if (allocation_site.is_null()) {
      allocation_site = isolate()->factory()->NewAllocationSite();
    }

    // Install the stub with an allocation site.
2827
    BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2828
    new_target = stub.GetCodeCopyFromTemplate(allocation_site);
2829 2830

    // Sanity check the trampoline stub.
2831
    DCHECK_EQ(*allocation_site, new_target->FindFirstAllocationSite());
2832 2833
  } else {
    // Install the generic stub.
2834
    BinaryOpICStub stub(isolate(), state);
2835
    new_target = stub.GetCode();
2836 2837

    // Sanity check the generic stub.
2838
    DCHECK_NULL(new_target->FindFirstAllocationSite());
2839
  }
2840
  set_target(*new_target);
2841

2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853
  if (FLAG_ic_stats &
      v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
    auto ic_stats = ICStats::instance();
    ic_stats->Begin();
    ICInfo& ic_info = ic_stats->Current();
    ic_info.type = "BinaryOpIC";
    ic_info.state = old_state.ToString();
    ic_info.state += " => ";
    ic_info.state += state.ToString();
    JavaScriptFrame::CollectTopFrameForICStats(isolate());
    ic_stats->End();
  } else if (FLAG_ic_stats) {
2854 2855 2856 2857 2858 2859 2860
    int line;
    int column;
    Address pc = GetAbstractPC(&line, &column);
    LOG(isolate(),
        BinaryOpIC(pc, line, column, *new_target, old_state.ToString().c_str(),
                   state.ToString().c_str(),
                   allocation_site.is_null() ? nullptr : *allocation_site));
2861
  }
2862

2863 2864
  // Patch the inlined smi code as necessary.
  if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2865
    PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
2866
  } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2867
    PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
2868
  }
2869

2870
  return result;
2871 2872
}

2873

2874
RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
2875
  HandleScope scope(isolate);
2876
  DCHECK_EQ(2, args.length());
2877
  typedef BinaryOpDescriptor Descriptor;
2878 2879
  Handle<Object> left = args.at(Descriptor::kLeft);
  Handle<Object> right = args.at(Descriptor::kRight);
2880
  BinaryOpIC ic(isolate);
2881 2882
  RETURN_RESULT_OR_FAILURE(
      isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
2883 2884 2885
}


2886
RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
2887
  HandleScope scope(isolate);
2888
  DCHECK_EQ(3, args.length());
2889
  typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
2890
  Handle<AllocationSite> allocation_site =
2891
      args.at<AllocationSite>(Descriptor::kAllocationSite);
2892 2893
  Handle<Object> left = args.at(Descriptor::kLeft);
  Handle<Object> right = args.at(Descriptor::kRight);
2894
  BinaryOpIC ic(isolate);
2895 2896
  RETURN_RESULT_OR_FAILURE(isolate,
                           ic.Transition(allocation_site, left, right));
2897 2898
}

2899 2900
Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
  CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2901 2902
                     CompareICState::UNINITIALIZED,
                     CompareICState::UNINITIALIZED);
2903
  Code* code = NULL;
2904
  CHECK(stub.FindCodeInCache(&code));
2905 2906 2907
  return code;
}

2908
Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2909
  HandleScope scope(isolate());
2910
  CompareICStub old_stub(target()->stub_key(), isolate());
2911 2912 2913 2914 2915
  CompareICState::State new_left =
      CompareICState::NewInputState(old_stub.left(), x);
  CompareICState::State new_right =
      CompareICState::NewInputState(old_stub.right(), y);
  CompareICState::State state = CompareICState::TargetState(
2916
      isolate(), old_stub.state(), old_stub.left(), old_stub.right(), op_,
2917
      HasInlinedSmiCode(address()), x, y);
2918
  CompareICStub stub(isolate(), op_, new_left, new_right, state);
2919
  if (state == CompareICState::KNOWN_RECEIVER) {
2920
    stub.set_known_map(
2921
        Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate()));
2922
  }
2923
  Handle<Code> new_target = stub.GetCode();
2924
  set_target(*new_target);
2925

2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
  if (FLAG_ic_stats &
      v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
    auto ic_stats = ICStats::instance();
    ic_stats->Begin();
    ICInfo& ic_info = ic_stats->Current();
    ic_info.type = "CompareIC";
    JavaScriptFrame::CollectTopFrameForICStats(isolate());
    ic_info.state = "((";
    ic_info.state += CompareICState::GetStateName(old_stub.left());
    ic_info.state += "+";
    ic_info.state += CompareICState::GetStateName(old_stub.right());
    ic_info.state += "=";
    ic_info.state += CompareICState::GetStateName(old_stub.state());
    ic_info.state += ")->(";
    ic_info.state += CompareICState::GetStateName(new_left);
    ic_info.state += "+";
    ic_info.state += CompareICState::GetStateName(new_right);
    ic_info.state += "=";
    ic_info.state += CompareICState::GetStateName(state);
    ic_info.state += "))#";
    ic_info.state += Token::Name(op_);
    ic_stats->End();
  } else if (FLAG_ic_stats) {
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959
    int line;
    int column;
    Address pc = GetAbstractPC(&line, &column);
    LOG(isolate(),
        CompareIC(pc, line, column, *stub.GetCode(), Token::Name(op_),
                  CompareICState::GetStateName(old_stub.left()),
                  CompareICState::GetStateName(old_stub.right()),
                  CompareICState::GetStateName(old_stub.state()),
                  CompareICState::GetStateName(new_left),
                  CompareICState::GetStateName(new_right),
                  CompareICState::GetStateName(state)));
2960 2961 2962
  }

  // Activate inlined smi code.
2963
  if (old_stub.state() == CompareICState::UNINITIALIZED) {
2964
    PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
2965
  }
2966 2967

  return *new_target;
2968 2969 2970
}


2971
// Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2972
RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
2973
  HandleScope scope(isolate);
2974
  DCHECK(args.length() == 3);
2975
  CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2976
  return ic.UpdateCaches(args.at(0), args.at(1));
2977 2978 2979
}


2980
RUNTIME_FUNCTION(Runtime_Unreachable) {
2981 2982 2983 2984 2985 2986
  UNREACHABLE();
  CHECK(false);
  return isolate->heap()->undefined_value();
}


2987
Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
verwaest's avatar
verwaest committed
2988
  ToBooleanICStub stub(isolate(), extra_ic_state());
2989
  ToBooleanHints old_hints = stub.hints();
2990
  bool to_boolean_value = stub.UpdateStatus(object);
2991
  ToBooleanHints new_hints = stub.hints();
2992
  Handle<Code> code = stub.GetCode();
2993
  set_target(*code);
2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018

  // Note: Although a no-op transition is semantically OK, it is hinting at a
  // bug somewhere in our state transition machinery.
  DCHECK_NE(old_hints, new_hints);
  if (V8_UNLIKELY(FLAG_ic_stats)) {
    if (FLAG_ic_stats &
        v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
      auto ic_stats = ICStats::instance();
      ic_stats->Begin();
      ICInfo& ic_info = ic_stats->Current();
      ic_info.type = "ToBooleanIC";
      ic_info.state = ToString(old_hints);
      ic_info.state += "=>";
      ic_info.state += ToString(new_hints);
      ic_stats->End();
    } else {
      int line;
      int column;
      Address pc = GetAbstractPC(&line, &column);
      LOG(isolate(),
          ToBooleanIC(pc, line, column, *code, ToString(old_hints).c_str(),
                      ToString(new_hints).c_str()));
    }
  }

3019
  return isolate()->factory()->ToBoolean(to_boolean_value);
3020 3021 3022
}


3023
RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
3024
  DCHECK(args.length() == 1);
3025
  HandleScope scope(isolate);
3026
  Handle<Object> object = args.at(0);
3027
  ToBooleanIC ic(isolate);
3028
  return *ic.ToBoolean(object);
3029 3030 3031
}


3032
RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
3033 3034
  Handle<JSObject> receiver = args.at<JSObject>(0);
  Handle<JSObject> holder = args.at<JSObject>(1);
3035
  Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
3036
  Handle<Name> name = args.at<Name>(3);
3037
  Handle<Object> value = args.at(4);
3038
  CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
3039 3040
  HandleScope scope(isolate);

3041
  if (V8_UNLIKELY(FLAG_runtime_stats)) {
3042 3043 3044 3045 3046
    RETURN_RESULT_OR_FAILURE(
        isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
                                            language_mode));
  }

3047
  Handle<AccessorInfo> callback(
3048
      callback_or_cell->IsWeakCell()
3049 3050
          ? AccessorInfo::cast(WeakCell::cast(*callback_or_cell)->value())
          : AccessorInfo::cast(*callback_or_cell));
3051

3052 3053 3054 3055 3056 3057 3058
  DCHECK(callback->IsCompatibleReceiver(*receiver));

  Address setter_address = v8::ToCData<Address>(callback->setter());
  v8::AccessorNameSetterCallback fun =
      FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
  DCHECK(fun != NULL);

3059 3060
  Object::ShouldThrow should_throw =
      is_sloppy(language_mode) ? Object::DONT_THROW : Object::THROW_ON_ERROR;
3061
  PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
3062
                                        *holder, should_throw);
3063
  custom_args.Call(fun, name, value);
3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075
  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
  return *value;
}


/**
 * Attempts to load a property with an interceptor (which must be present),
 * but doesn't search the prototype chain.
 *
 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
 * provide any value for the given name.
 */
3076
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
3077
  DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
3078
  Handle<Name> name =
3079
      args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
3080
  Handle<Object> receiver =
3081
      args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
3082 3083 3084
  Handle<JSObject> holder =
      args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
  HandleScope scope(isolate);
3085

3086 3087 3088 3089 3090
  if (!receiver->IsJSReceiver()) {
    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
        isolate, receiver, Object::ConvertReceiver(isolate, receiver));
  }

3091 3092 3093 3094 3095 3096 3097
  InterceptorInfo* interceptor = holder->GetNamedInterceptor();
  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
                                      *holder, Object::DONT_THROW);

  v8::GenericNamedPropertyGetterCallback getter =
      v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
          interceptor->getter());
3098
  Handle<Object> result = arguments.Call(getter, name);
3099 3100 3101

  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);

3102 3103
  if (!result.is_null()) return *result;
  return isolate->heap()->no_interceptor_result_sentinel();
3104 3105 3106 3107 3108 3109 3110
}


/**
 * Loads a property with an interceptor performing post interceptor
 * lookup if interceptor failed.
 */
3111
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
3112
  HandleScope scope(isolate);
3113
  DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2);
3114 3115
  Handle<Name> name =
      args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
3116
  Handle<Object> receiver =
3117
      args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
3118 3119 3120
  Handle<JSObject> holder =
      args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);

3121 3122 3123 3124 3125
  if (!receiver->IsJSReceiver()) {
    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
        isolate, receiver, Object::ConvertReceiver(isolate, receiver));
  }

3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138
  InterceptorInfo* interceptor = holder->GetNamedInterceptor();
  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
                                      *holder, Object::DONT_THROW);

  v8::GenericNamedPropertyGetterCallback getter =
      v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
          interceptor->getter());
  Handle<Object> result = arguments.Call(getter, name);

  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);

  if (!result.is_null()) return *result;

3139
  LookupIterator it(receiver, name, holder);
3140 3141 3142 3143 3144 3145 3146 3147
  // Skip any lookup work until we hit the (possibly non-masking) interceptor.
  while (it.state() != LookupIterator::INTERCEPTOR ||
         !it.GetHolder<JSObject>().is_identical_to(holder)) {
    DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
    it.Next();
  }
  // Skip past the interceptor.
  it.Next();
3148
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
3149 3150 3151

  if (it.IsFound()) return *result;

3152
  Handle<Smi> slot = args.at<Smi>(3);
3153
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
3154 3155
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
  FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
3156 3157 3158
  // It could actually be any kind of load IC slot here but the predicate
  // handles all the cases properly.
  if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
3159 3160
    return isolate->heap()->undefined_value();
  }
3161

3162 3163 3164
  // Throw a reference error.
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
3165 3166 3167
}


3168
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
3169
  HandleScope scope(isolate);
3170 3171 3172 3173
  DCHECK_EQ(5, args.length());
  // Runtime functions don't follow the IC's calling convention.
  Handle<Object> value = args.at(0);
  Handle<Smi> slot = args.at<Smi>(1);
3174
  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
3175 3176
  Handle<JSObject> receiver = args.at<JSObject>(3);
  Handle<Name> name = args.at<Name>(4);
3177
  FeedbackSlot vector_slot = vector->ToSlot(slot->value());
3178
  LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197

  DCHECK(receiver->HasNamedInterceptor());
  InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
  DCHECK(!interceptor->non_masking());
  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
                                      *receiver, Object::DONT_THROW);

  v8::GenericNamedPropertySetterCallback setter =
      v8::ToCData<v8::GenericNamedPropertySetterCallback>(
          interceptor->setter());
  Handle<Object> result = arguments.Call(setter, name, value);
  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
  if (!result.is_null()) return *value;

  LookupIterator it(receiver, name, receiver);
  // Skip past any access check on the receiver.
  if (it.state() == LookupIterator::ACCESS_CHECK) {
    DCHECK(it.HasAccess());
    it.Next();
3198
  }
3199 3200 3201 3202
  // Skip past the interceptor on the receiver.
  DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
  it.Next();

3203
  MAYBE_RETURN(Object::SetProperty(&it, value, language_mode,
3204 3205 3206
                                   JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED),
               isolate->heap()->exception());
  return *value;
3207 3208 3209
}


3210
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
3211
  // TODO(verwaest): This should probably get the holder and receiver as input.
3212 3213 3214 3215
  HandleScope scope(isolate);
  Handle<JSObject> receiver = args.at<JSObject>(0);
  DCHECK(args.smi_at(1) >= 0);
  uint32_t index = args.smi_at(1);
3216 3217 3218 3219 3220 3221 3222

  InterceptorInfo* interceptor = receiver->GetIndexedInterceptor();
  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
                                      *receiver, Object::DONT_THROW);

  v8::IndexedPropertyGetterCallback getter =
      v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
3223
  Handle<Object> result = arguments.Call(getter, index);
3224 3225 3226

  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);

3227
  if (result.is_null()) {
3228 3229 3230
    LookupIterator it(isolate, receiver, index, receiver);
    DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
    it.Next();
3231
    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
3232 3233 3234
                                       Object::GetProperty(&it));
  }

3235
  return *result;
3236
}
3237 3238
}  // namespace internal
}  // namespace v8