The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ic.cc @ f230a1cf

History | View | Annotate | Download (96.3 KB)

1
// Copyright 2012 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include "v8.h"
29

    
30
#include "accessors.h"
31
#include "api.h"
32
#include "arguments.h"
33
#include "codegen.h"
34
#include "execution.h"
35
#include "ic-inl.h"
36
#include "runtime.h"
37
#include "stub-cache.h"
38

    
39
namespace v8 {
40
namespace internal {
41

    
42
#ifdef DEBUG
43
char IC::TransitionMarkFromState(IC::State state) {
44
  switch (state) {
45
    case UNINITIALIZED: return '0';
46
    case PREMONOMORPHIC: return '.';
47
    case MONOMORPHIC: return '1';
48
    case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
49
    case POLYMORPHIC: return 'P';
50
    case MEGAMORPHIC: return 'N';
51
    case GENERIC: return 'G';
52

    
53
    // We never see the debugger states here, because the state is
54
    // computed from the original code - not the patched code. Let
55
    // these cases fall through to the unreachable code below.
56
    case DEBUG_STUB: break;
57
  }
58
  UNREACHABLE();
59
  return 0;
60
}
61

    
62

    
63
const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
64
  if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
65
  if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
66
    return ".IGNORE_OOB";
67
  }
68
  if (IsGrowStoreMode(mode)) return ".GROW";
69
  return "";
70
}
71

    
72

    
73
void IC::TraceIC(const char* type,
74
                 Handle<Object> name) {
75
  if (FLAG_trace_ic) {
76
    Code* new_target = raw_target();
77
    State new_state = new_target->ic_state();
78
    PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
79
    StackFrameIterator it(isolate());
80
    while (it.frame()->fp() != this->fp()) it.Advance();
81
    StackFrame* raw_frame = it.frame();
82
    if (raw_frame->is_internal()) {
83
      Code* apply_builtin = isolate()->builtins()->builtin(
84
          Builtins::kFunctionApply);
85
      if (raw_frame->unchecked_code() == apply_builtin) {
86
        PrintF("apply from ");
87
        it.Advance();
88
        raw_frame = it.frame();
89
      }
90
    }
91
    JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
92
    Code::ExtraICState extra_state = new_target->extra_ic_state();
93
    const char* modifier =
94
        GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(extra_state));
95
    PrintF(" (%c->%c%s)",
96
           TransitionMarkFromState(state()),
97
           TransitionMarkFromState(new_state),
98
           modifier);
99
    name->Print();
100
    PrintF("]\n");
101
  }
102
}
103

    
104
#define TRACE_GENERIC_IC(isolate, type, reason)                 \
105
  do {                                                          \
106
    if (FLAG_trace_ic) {                                        \
107
      PrintF("[%s patching generic stub in ", type);            \
108
      JavaScriptFrame::PrintTop(isolate, stdout, false, true);  \
109
      PrintF(" (%s)]\n", reason);                               \
110
    }                                                           \
111
  } while (false)
112

    
113
#else
114
#define TRACE_GENERIC_IC(isolate, type, reason)
115
#endif  // DEBUG
116

    
117
#define TRACE_IC(type, name)             \
118
  ASSERT((TraceIC(type, name), true))
119

    
120
IC::IC(FrameDepth depth, Isolate* isolate)
121
    : isolate_(isolate),
122
      target_set_(false) {
123
  // To improve the performance of the (much used) IC code, we unfold a few
124
  // levels of the stack frame iteration code. This yields a ~35% speedup when
125
  // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
126
  const Address entry =
127
      Isolate::c_entry_fp(isolate->thread_local_top());
128
  Address* pc_address =
129
      reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
130
  Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
131
  // If there's another JavaScript frame on the stack or a
132
  // StubFailureTrampoline, we need to look one frame further down the stack to
133
  // find the frame pointer and the return address stack slot.
134
  if (depth == EXTRA_CALL_FRAME) {
135
    const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
136
    pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
137
    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
138
  }
139
#ifdef DEBUG
140
  StackFrameIterator it(isolate);
141
  for (int i = 0; i < depth + 1; i++) it.Advance();
142
  StackFrame* frame = it.frame();
143
  ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
144
#endif
145
  fp_ = fp;
146
  pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
147
  target_ = handle(raw_target(), isolate);
148
  state_ = target_->ic_state();
149
}
150

    
151

    
152
#ifdef ENABLE_DEBUGGER_SUPPORT
153
Address IC::OriginalCodeAddress() const {
154
  HandleScope scope(isolate());
155
  // Compute the JavaScript frame for the frame pointer of this IC
156
  // structure. We need this to be able to find the function
157
  // corresponding to the frame.
158
  StackFrameIterator it(isolate());
159
  while (it.frame()->fp() != this->fp()) it.Advance();
160
  JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
161
  // Find the function on the stack and both the active code for the
162
  // function and the original code.
163
  JSFunction* function = frame->function();
164
  Handle<SharedFunctionInfo> shared(function->shared(), isolate());
165
  Code* code = shared->code();
166
  ASSERT(Debug::HasDebugInfo(shared));
167
  Code* original_code = Debug::GetDebugInfo(shared)->original_code();
168
  ASSERT(original_code->IsCode());
169
  // Get the address of the call site in the active code. This is the
170
  // place where the call to DebugBreakXXX is and where the IC
171
  // normally would be.
172
  Address addr = Assembler::target_address_from_return_address(pc());
173
  // Return the address in the original code. This is the place where
174
  // the call which has been overwritten by the DebugBreakXXX resides
175
  // and the place where the inline cache system should look.
176
  intptr_t delta =
177
      original_code->instruction_start() - code->instruction_start();
178
  return addr + delta;
179
}
180
#endif
181

    
182

    
183
static bool HasInterceptorGetter(JSObject* object) {
184
  return !object->GetNamedInterceptor()->getter()->IsUndefined();
185
}
186

    
187

    
188
static bool HasInterceptorSetter(JSObject* object) {
189
  return !object->GetNamedInterceptor()->setter()->IsUndefined();
190
}
191

    
192

    
193
static void LookupForRead(Handle<Object> object,
194
                          Handle<String> name,
195
                          LookupResult* lookup) {
196
  // Skip all the objects with named interceptors, but
197
  // without actual getter.
198
  while (true) {
199
    object->Lookup(*name, lookup);
200
    // Besides normal conditions (property not found or it's not
201
    // an interceptor), bail out if lookup is not cacheable: we won't
202
    // be able to IC it anyway and regular lookup should work fine.
203
    if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
204
      return;
205
    }
206

    
207
    Handle<JSObject> holder(lookup->holder(), lookup->isolate());
208
    if (HasInterceptorGetter(*holder)) {
209
      return;
210
    }
211

    
212
    holder->LocalLookupRealNamedProperty(*name, lookup);
213
    if (lookup->IsFound()) {
214
      ASSERT(!lookup->IsInterceptor());
215
      return;
216
    }
217

    
218
    Handle<Object> proto(holder->GetPrototype(), lookup->isolate());
219
    if (proto->IsNull()) {
220
      ASSERT(!lookup->IsFound());
221
      return;
222
    }
223

    
224
    object = proto;
225
  }
226
}
227

    
228

    
229
bool CallIC::TryUpdateExtraICState(LookupResult* lookup,
230
                                   Handle<Object> object) {
231
  if (!lookup->IsConstantFunction()) return false;
232
  JSFunction* function = lookup->GetConstantFunction();
233
  if (!function->shared()->HasBuiltinFunctionId()) return false;
234

    
235
  // Fetch the arguments passed to the called function.
236
  const int argc = target()->arguments_count();
237
  Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
238
  Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
239
  Arguments args(argc + 1,
240
                 &Memory::Object_at(fp +
241
                                    StandardFrameConstants::kCallerSPOffset +
242
                                    argc * kPointerSize));
243
  switch (function->shared()->builtin_function_id()) {
244
    case kStringCharCodeAt:
245
    case kStringCharAt:
246
      if (object->IsString()) {
247
        String* string = String::cast(*object);
248
        // Check there's the right string value or wrapper in the receiver slot.
249
        ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
250
        // If we're in the default (fastest) state and the index is
251
        // out of bounds, update the state to record this fact.
252
        if (StringStubState::decode(extra_ic_state()) == DEFAULT_STRING_STUB &&
253
            argc >= 1 && args[1]->IsNumber()) {
254
          double index = DoubleToInteger(args.number_at(1));
255
          if (index < 0 || index >= string->length()) {
256
            extra_ic_state_ =
257
                StringStubState::update(extra_ic_state(),
258
                                        STRING_INDEX_OUT_OF_BOUNDS);
259
            return true;
260
          }
261
        }
262
      }
263
      break;
264
    default:
265
      return false;
266
  }
267
  return false;
268
}
269

    
270

    
271
bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
272
                                                Handle<String> name) {
273
  DisallowHeapAllocation no_gc;
274

    
275
  if (target()->is_call_stub()) {
276
    LookupResult lookup(isolate());
277
    LookupForRead(receiver, name, &lookup);
278
    if (static_cast<CallIC*>(this)->TryUpdateExtraICState(&lookup, receiver)) {
279
      return true;
280
    }
281
  }
282

    
283
  if (target()->is_keyed_stub()) {
284
    // Determine whether the failure is due to a name failure.
285
    if (!name->IsName()) return false;
286
    Name* stub_name = target()->FindFirstName();
287
    if (*name != stub_name) return false;
288
  }
289

    
290
  InlineCacheHolderFlag cache_holder =
291
      Code::ExtractCacheHolderFromFlags(target()->flags());
292

    
293
  switch (cache_holder) {
294
    case OWN_MAP:
295
      // The stub was generated for JSObject but called for non-JSObject.
296
      // IC::GetCodeCacheHolder is not applicable.
297
      if (!receiver->IsJSObject()) return false;
298
      break;
299
    case PROTOTYPE_MAP:
300
      // IC::GetCodeCacheHolder is not applicable.
301
      if (receiver->GetPrototype(isolate())->IsNull()) return false;
302
      break;
303
  }
304

    
305
  Handle<Map> map(
306
      IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
307

    
308
  // Decide whether the inline cache failed because of changes to the
309
  // receiver itself or changes to one of its prototypes.
310
  //
311
  // If there are changes to the receiver itself, the map of the
312
  // receiver will have changed and the current target will not be in
313
  // the receiver map's code cache.  Therefore, if the current target
314
  // is in the receiver map's code cache, the inline cache failed due
315
  // to prototype check failure.
316
  int index = map->IndexInCodeCache(*name, *target());
317
  if (index >= 0) {
318
    map->RemoveFromCodeCache(*name, *target(), index);
319
    // Handlers are stored in addition to the ICs on the map. Remove those, too.
320
    TryRemoveInvalidHandlers(map, name);
321
    return true;
322
  }
323

    
324
  // The stub is not in the cache. We've ruled out all other kinds of failure
325
  // except for proptotype chain changes, a deprecated map, a map that's
326
  // different from the one that the stub expects, elements kind changes, or a
327
  // constant global property that will become mutable. Threat all those
328
  // situations as prototype failures (stay monomorphic if possible).
329

    
330
  // If the IC is shared between multiple receivers (slow dictionary mode), then
331
  // the map cannot be deprecated and the stub invalidated.
332
  if (cache_holder == OWN_MAP) {
333
    Map* old_map = target()->FindFirstMap();
334
    if (old_map == *map) return true;
335
    if (old_map != NULL) {
336
      if (old_map->is_deprecated()) return true;
337
      if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
338
                                              map->elements_kind())) {
339
        return true;
340
      }
341
    }
342
  }
343

    
344
  if (receiver->IsGlobalObject()) {
345
    LookupResult lookup(isolate());
346
    GlobalObject* global = GlobalObject::cast(*receiver);
347
    global->LocalLookupRealNamedProperty(*name, &lookup);
348
    if (!lookup.IsFound()) return false;
349
    PropertyCell* cell = global->GetPropertyCell(&lookup);
350
    return cell->type()->IsConstant();
351
  }
352

    
353
  return false;
354
}
355

    
356

    
357
void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
358
  CodeHandleList handlers;
359
  target()->FindHandlers(&handlers);
360
  for (int i = 0; i < handlers.length(); i++) {
361
    Handle<Code> handler = handlers.at(i);
362
    int index = map->IndexInCodeCache(*name, *handler);
363
    if (index >= 0) {
364
      map->RemoveFromCodeCache(*name, *handler, index);
365
      return;
366
    }
367
  }
368
}
369

    
370

    
371
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
372
  if (!name->IsString()) return;
373
  if (state() != MONOMORPHIC) {
374
    if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
375
      TryRemoveInvalidHandlers(
376
          handle(Handle<HeapObject>::cast(receiver)->map()),
377
          Handle<String>::cast(name));
378
    }
379
    return;
380
  }
381
  if (receiver->IsUndefined() || receiver->IsNull()) return;
382

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

    
391
  // The builtins object is special.  It only changes when JavaScript
392
  // builtins are loaded lazily.  It is important to keep inline
393
  // caches for the builtins object monomorphic.  Therefore, if we get
394
  // an inline cache miss for the builtins object after lazily loading
395
  // JavaScript builtins, we return uninitialized as the state to
396
  // force the inline cache back to monomorphic state.
397
  if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED;
398
}
399

    
400

    
401
RelocInfo::Mode IC::ComputeMode() {
402
  Address addr = address();
403
  Code* code = Code::cast(isolate()->FindCodeObject(addr));
404
  for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
405
       !it.done(); it.next()) {
406
    RelocInfo* info = it.rinfo();
407
    if (info->pc() == addr) return info->rmode();
408
  }
409
  UNREACHABLE();
410
  return RelocInfo::NONE32;
411
}
412

    
413

    
414
Failure* IC::TypeError(const char* type,
415
                       Handle<Object> object,
416
                       Handle<Object> key) {
417
  HandleScope scope(isolate());
418
  Handle<Object> args[2] = { key, object };
419
  Handle<Object> error = isolate()->factory()->NewTypeError(
420
      type, HandleVector(args, 2));
421
  return isolate()->Throw(*error);
422
}
423

    
424

    
425
Failure* IC::ReferenceError(const char* type, Handle<String> name) {
426
  HandleScope scope(isolate());
427
  Handle<Object> error = isolate()->factory()->NewReferenceError(
428
      type, HandleVector(&name, 1));
429
  return isolate()->Throw(*error);
430
}
431

    
432

    
433
static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) {
434
  bool was_uninitialized =
435
      old_state == UNINITIALIZED || old_state == PREMONOMORPHIC;
436
  bool is_uninitialized =
437
      new_state == UNINITIALIZED || new_state == PREMONOMORPHIC;
438
  return (was_uninitialized && !is_uninitialized) ?  1 :
439
         (!was_uninitialized && is_uninitialized) ? -1 : 0;
440
}
441

    
442

    
443
void IC::PostPatching(Address address, Code* target, Code* old_target) {
444
  if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) {
445
    return;
446
  }
447
  Isolate* isolate = target->GetHeap()->isolate();
448
  Code* host = isolate->
449
      inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
450
  if (host->kind() != Code::FUNCTION) return;
451

    
452
  if (FLAG_type_info_threshold > 0 &&
453
      old_target->is_inline_cache_stub() &&
454
      target->is_inline_cache_stub()) {
455
    int delta = ComputeTypeInfoCountDelta(old_target->ic_state(),
456
                                          target->ic_state());
457
    // Not all Code objects have TypeFeedbackInfo.
458
    if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) {
459
      TypeFeedbackInfo* info =
460
          TypeFeedbackInfo::cast(host->type_feedback_info());
461
      info->change_ic_with_type_info_count(delta);
462
    }
463
  }
464
  if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
465
    TypeFeedbackInfo* info =
466
        TypeFeedbackInfo::cast(host->type_feedback_info());
467
    info->change_own_type_change_checksum();
468
  }
469
  if (FLAG_watch_ic_patching) {
470
    host->set_profiler_ticks(0);
471
    isolate->runtime_profiler()->NotifyICChanged();
472
  }
473
  // TODO(2029): When an optimized function is patched, it would
474
  // be nice to propagate the corresponding type information to its
475
  // unoptimized version for the benefit of later inlining.
476
}
477

    
478

    
479
void IC::Clear(Isolate* isolate, Address address) {
480
  Code* target = GetTargetAtAddress(address);
481

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

    
485
  switch (target->kind()) {
486
    case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target);
487
    case Code::KEYED_LOAD_IC:
488
      return KeyedLoadIC::Clear(isolate, address, target);
489
    case Code::STORE_IC: return StoreIC::Clear(isolate, address, target);
490
    case Code::KEYED_STORE_IC:
491
      return KeyedStoreIC::Clear(isolate, address, target);
492
    case Code::CALL_IC: return CallIC::Clear(address, target);
493
    case Code::KEYED_CALL_IC:  return KeyedCallIC::Clear(address, target);
494
    case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target);
495
    case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
496
    case Code::BINARY_OP_IC:
497
    case Code::TO_BOOLEAN_IC:
498
      // Clearing these is tricky and does not
499
      // make any performance difference.
500
      return;
501
    default: UNREACHABLE();
502
  }
503
}
504

    
505

    
506
void CallICBase::Clear(Address address, Code* target) {
507
  if (IsCleared(target)) return;
508
  bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
509
  Code* code =
510
      target->GetIsolate()->stub_cache()->FindCallInitialize(
511
          target->arguments_count(),
512
          contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
513
          target->kind());
514
  SetTargetAtAddress(address, code);
515
}
516

    
517

    
518
void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) {
519
  if (IsCleared(target)) return;
520
  // Make sure to also clear the map used in inline fast cases.  If we
521
  // do not clear these maps, cached code can keep objects alive
522
  // through the embedded maps.
523
  SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
524
}
525

    
526

    
527
void LoadIC::Clear(Isolate* isolate, Address address, Code* target) {
528
  if (IsCleared(target)) return;
529
  SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
530
}
531

    
532

    
533
void StoreIC::Clear(Isolate* isolate, Address address, Code* target) {
534
  if (IsCleared(target)) return;
535
  SetTargetAtAddress(address,
536
      *pre_monomorphic_stub(
537
          isolate, Code::GetStrictMode(target->extra_ic_state())));
538
}
539

    
540

    
541
void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) {
542
  if (IsCleared(target)) return;
543
  SetTargetAtAddress(address,
544
      *pre_monomorphic_stub(
545
          isolate, Code::GetStrictMode(target->extra_ic_state())));
546
}
547

    
548

    
549
void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
550
  ASSERT(target->major_key() == CodeStub::CompareIC);
551
  CompareIC::State handler_state;
552
  Token::Value op;
553
  ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL,
554
                                &handler_state, &op);
555
  // Only clear CompareICs that can retain objects.
556
  if (handler_state != KNOWN_OBJECT) return;
557
  SetTargetAtAddress(address, GetRawUninitialized(isolate, op));
558
  PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
559
}
560

    
561

    
562
Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
563
  Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object);
564

    
565
  if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
566
    // Patch the receiver and use the delegate as the function to
567
    // invoke. This is used for invoking objects as if they were functions.
568
    const int argc = target()->arguments_count();
569
    StackFrameLocator locator(isolate());
570
    JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
571
    int index = frame->ComputeExpressionsCount() - (argc + 1);
572
    frame->SetExpression(index, *object);
573
  }
574

    
575
  return delegate;
576
}
577

    
578

    
579
void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
580
                                            Handle<Object> object) {
581
  while (callee->IsJSFunctionProxy()) {
582
    callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(),
583
                            isolate());
584
  }
585

    
586
  if (callee->IsJSFunction()) {
587
    Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
588
    if (!function->shared()->is_classic_mode() || function->IsBuiltin()) {
589
      // Do not wrap receiver for strict mode functions or for builtins.
590
      return;
591
    }
592
  }
593

    
594
  // And only wrap string, number or boolean.
595
  if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
596
    // Change the receiver to the result of calling ToObject on it.
597
    const int argc = this->target()->arguments_count();
598
    StackFrameLocator locator(isolate());
599
    JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
600
    int index = frame->ComputeExpressionsCount() - (argc + 1);
601
    frame->SetExpression(index, *isolate()->factory()->ToObject(object));
602
  }
603
}
604

    
605

    
606
static bool MigrateDeprecated(Handle<Object> object) {
607
  if (!object->IsJSObject()) return false;
608
  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
609
  if (!receiver->map()->is_deprecated()) return false;
610
  JSObject::MigrateInstance(Handle<JSObject>::cast(object));
611
  return true;
612
}
613

    
614

    
615
MaybeObject* CallICBase::LoadFunction(Handle<Object> object,
616
                                      Handle<String> name) {
617
  bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
618

    
619
  // If the object is undefined or null it's illegal to try to get any
620
  // of its properties; throw a TypeError in that case.
621
  if (object->IsUndefined() || object->IsNull()) {
622
    return TypeError("non_object_property_call", object, name);
623
  }
624

    
625
  // Check if the name is trivially convertible to an index and get
626
  // the element if so.
627
  uint32_t index;
628
  if (name->AsArrayIndex(&index)) {
629
    Handle<Object> result = Object::GetElement(isolate(), object, index);
630
    RETURN_IF_EMPTY_HANDLE(isolate(), result);
631
    if (result->IsJSFunction()) return *result;
632

    
633
    // Try to find a suitable function delegate for the object at hand.
634
    result = TryCallAsFunction(result);
635
    if (result->IsJSFunction()) return *result;
636

    
637
    // Otherwise, it will fail in the lookup step.
638
  }
639

    
640
  // Lookup the property in the object.
641
  LookupResult lookup(isolate());
642
  LookupForRead(object, name, &lookup);
643

    
644
  if (!lookup.IsFound()) {
645
    // If the object does not have the requested property, check which
646
    // exception we need to throw.
647
    return IsUndeclaredGlobal(object)
648
        ? ReferenceError("not_defined", name)
649
        : TypeError("undefined_method", object, name);
650
  }
651

    
652
  // Lookup is valid: Update inline cache and stub cache.
653
  if (use_ic) UpdateCaches(&lookup, object, name);
654

    
655
  // Get the property.
656
  PropertyAttributes attr;
657
  Handle<Object> result =
658
      Object::GetProperty(object, object, &lookup, name, &attr);
659
  RETURN_IF_EMPTY_HANDLE(isolate(), result);
660

    
661
  if (lookup.IsInterceptor() && attr == ABSENT) {
662
    // If the object does not have the requested property, check which
663
    // exception we need to throw.
664
    return IsUndeclaredGlobal(object)
665
        ? ReferenceError("not_defined", name)
666
        : TypeError("undefined_method", object, name);
667
  }
668

    
669
  ASSERT(!result->IsTheHole());
670

    
671
  // Make receiver an object if the callee requires it. Strict mode or builtin
672
  // functions do not wrap the receiver, non-strict functions and objects
673
  // called as functions do.
674
  ReceiverToObjectIfRequired(result, object);
675

    
676
  if (result->IsJSFunction()) {
677
    Handle<JSFunction> function = Handle<JSFunction>::cast(result);
678
#ifdef ENABLE_DEBUGGER_SUPPORT
679
    // Handle stepping into a function if step into is active.
680
    Debug* debug = isolate()->debug();
681
    if (debug->StepInActive()) {
682
      // Protect the result in a handle as the debugger can allocate and might
683
      // cause GC.
684
      debug->HandleStepIn(function, object, fp(), false);
685
    }
686
#endif
687
    return *function;
688
  }
689

    
690
  // Try to find a suitable function delegate for the object at hand.
691
  result = TryCallAsFunction(result);
692
  if (result->IsJSFunction()) return *result;
693

    
694
  return TypeError("property_not_function", object, name);
695
}
696

    
697

    
698
Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
699
                                                Handle<Object> object,
700
                                                Handle<String> name) {
701
  int argc = target()->arguments_count();
702
  Handle<JSObject> holder(lookup->holder(), isolate());
703
  switch (lookup->type()) {
704
    case FIELD: {
705
      PropertyIndex index = lookup->GetFieldIndex();
706
      return isolate()->stub_cache()->ComputeCallField(
707
          argc, kind_, extra_ic_state(), name, object, holder, index);
708
    }
709
    case CONSTANT: {
710
      if (!lookup->IsConstantFunction()) return Handle<Code>::null();
711
      // Get the constant function and compute the code stub for this
712
      // call; used for rewriting to monomorphic state and making sure
713
      // that the code stub is in the stub cache.
714
      Handle<JSFunction> function(lookup->GetConstantFunction(), isolate());
715
      return isolate()->stub_cache()->ComputeCallConstant(
716
          argc, kind_, extra_ic_state(), name, object, holder, function);
717
    }
718
    case NORMAL: {
719
      // If we return a null handle, the IC will not be patched.
720
      if (!object->IsJSObject()) return Handle<Code>::null();
721
      Handle<JSObject> receiver = Handle<JSObject>::cast(object);
722

    
723
      if (holder->IsGlobalObject()) {
724
        Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
725
        Handle<PropertyCell> cell(
726
            global->GetPropertyCell(lookup), isolate());
727
        if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
728
        Handle<JSFunction> function(JSFunction::cast(cell->value()));
729
        return isolate()->stub_cache()->ComputeCallGlobal(
730
            argc, kind_, extra_ic_state(), name,
731
            receiver, global, cell, function);
732
      } else {
733
        // There is only one shared stub for calling normalized
734
        // properties. It does not traverse the prototype chain, so the
735
        // property must be found in the receiver for the stub to be
736
        // applicable.
737
        if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
738
        return isolate()->stub_cache()->ComputeCallNormal(
739
            argc, kind_, extra_ic_state());
740
      }
741
      break;
742
    }
743
    case INTERCEPTOR:
744
      ASSERT(HasInterceptorGetter(*holder));
745
      return isolate()->stub_cache()->ComputeCallInterceptor(
746
          argc, kind_, extra_ic_state(), name, object, holder);
747
    default:
748
      return Handle<Code>::null();
749
  }
750
}
751

    
752

    
753
Handle<Code> CallICBase::megamorphic_stub() {
754
  return isolate()->stub_cache()->ComputeCallMegamorphic(
755
      target()->arguments_count(), kind_, extra_ic_state());
756
}
757

    
758

    
759
Handle<Code> CallICBase::pre_monomorphic_stub() {
760
  return isolate()->stub_cache()->ComputeCallPreMonomorphic(
761
      target()->arguments_count(), kind_, extra_ic_state());
762
}
763

    
764

    
765
void CallICBase::UpdateCaches(LookupResult* lookup,
766
                              Handle<Object> object,
767
                              Handle<String> name) {
768
  // Bail out if we didn't find a result.
769
  if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
770

    
771
  // Compute the number of arguments.
772
  Handle<Code> code;
773
  code = state() == UNINITIALIZED
774
      ? pre_monomorphic_stub()
775
      : ComputeMonomorphicStub(lookup, object, name);
776

    
777
  // If there's no appropriate stub we simply avoid updating the caches.
778
  // TODO(verwaest): Install a slow fallback in this case to avoid not learning,
779
  // and deopting Crankshaft code.
780
  if (code.is_null()) return;
781

    
782
  Handle<JSObject> cache_object = object->IsJSObject()
783
      ? Handle<JSObject>::cast(object)
784
      : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
785
                         isolate());
786

    
787
  PatchCache(cache_object, name, code);
788
  TRACE_IC("CallIC", name);
789
}
790

    
791

    
792
MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object,
793
                                       Handle<Object> key) {
794
  if (key->IsInternalizedString()) {
795
    return CallICBase::LoadFunction(object, Handle<String>::cast(key));
796
  }
797

    
798
  if (object->IsUndefined() || object->IsNull()) {
799
    return TypeError("non_object_property_call", object, key);
800
  }
801

    
802
  bool use_ic = MigrateDeprecated(object)
803
      ? false : FLAG_use_ic && !object->IsAccessCheckNeeded();
804

    
805
  if (use_ic && state() != MEGAMORPHIC) {
806
    ASSERT(!object->IsJSGlobalProxy());
807
    int argc = target()->arguments_count();
808
    Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic(
809
        argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
810
    if (object->IsJSObject()) {
811
      Handle<JSObject> receiver = Handle<JSObject>::cast(object);
812
      if (receiver->elements()->map() ==
813
          isolate()->heap()->non_strict_arguments_elements_map()) {
814
        stub = isolate()->stub_cache()->ComputeCallArguments(argc);
815
      }
816
    }
817
    ASSERT(!stub.is_null());
818
    set_target(*stub);
819
    TRACE_IC("CallIC", key);
820
  }
821

    
822
  Handle<Object> result = GetProperty(isolate(), object, key);
823
  RETURN_IF_EMPTY_HANDLE(isolate(), result);
824

    
825
  // Make receiver an object if the callee requires it. Strict mode or builtin
826
  // functions do not wrap the receiver, non-strict functions and objects
827
  // called as functions do.
828
  ReceiverToObjectIfRequired(result, object);
829
  if (result->IsJSFunction()) return *result;
830

    
831
  result = TryCallAsFunction(result);
832
  if (result->IsJSFunction()) return *result;
833

    
834
  return TypeError("property_not_function", object, key);
835
}
836

    
837

    
838
MaybeObject* LoadIC::Load(Handle<Object> object,
839
                          Handle<String> name) {
840
  // If the object is undefined or null it's illegal to try to get any
841
  // of its properties; throw a TypeError in that case.
842
  if (object->IsUndefined() || object->IsNull()) {
843
    return TypeError("non_object_property_load", object, name);
844
  }
845

    
846
  if (FLAG_use_ic) {
847
    // Use specialized code for getting the length of strings and
848
    // string wrapper objects.  The length property of string wrapper
849
    // objects is read-only and therefore always returns the length of
850
    // the underlying string value.  See ECMA-262 15.5.5.1.
851
    if (object->IsStringWrapper() &&
852
        name->Equals(isolate()->heap()->length_string())) {
853
      Handle<Code> stub;
854
      if (state() == UNINITIALIZED) {
855
        stub = pre_monomorphic_stub();
856
      } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
857
        StringLengthStub string_length_stub(kind());
858
        stub = string_length_stub.GetCode(isolate());
859
      } else if (state() != MEGAMORPHIC) {
860
        ASSERT(state() != GENERIC);
861
        stub = megamorphic_stub();
862
      }
863
      if (!stub.is_null()) {
864
        set_target(*stub);
865
#ifdef DEBUG
866
        if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
867
#endif
868
      }
869
      // Get the string if we have a string wrapper object.
870
      String* string = String::cast(JSValue::cast(*object)->value());
871
      return Smi::FromInt(string->length());
872
    }
873

    
874
    // Use specialized code for getting prototype of functions.
875
    if (object->IsJSFunction() &&
876
        name->Equals(isolate()->heap()->prototype_string()) &&
877
        Handle<JSFunction>::cast(object)->should_have_prototype()) {
878
      Handle<Code> stub;
879
      if (state() == UNINITIALIZED) {
880
        stub = pre_monomorphic_stub();
881
      } else if (state() == PREMONOMORPHIC) {
882
        FunctionPrototypeStub function_prototype_stub(kind());
883
        stub = function_prototype_stub.GetCode(isolate());
884
      } else if (state() != MEGAMORPHIC) {
885
        ASSERT(state() != GENERIC);
886
        stub = megamorphic_stub();
887
      }
888
      if (!stub.is_null()) {
889
        set_target(*stub);
890
#ifdef DEBUG
891
        if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
892
#endif
893
      }
894
      return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object));
895
    }
896
  }
897

    
898
  // Check if the name is trivially convertible to an index and get
899
  // the element or char if so.
900
  uint32_t index;
901
  if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
902
    // Rewrite to the generic keyed load stub.
903
    if (FLAG_use_ic) set_target(*generic_stub());
904
    return Runtime::GetElementOrCharAtOrFail(isolate(), object, index);
905
  }
906

    
907
  bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
908

    
909
  // Named lookup in the object.
910
  LookupResult lookup(isolate());
911
  LookupForRead(object, name, &lookup);
912

    
913
  // If we did not find a property, check if we need to throw an exception.
914
  if (!lookup.IsFound()) {
915
    if (IsUndeclaredGlobal(object)) {
916
      return ReferenceError("not_defined", name);
917
    }
918
    LOG(isolate(), SuspectReadEvent(*name, *object));
919
  }
920

    
921
  // Update inline cache and stub cache.
922
  if (use_ic) UpdateCaches(&lookup, object, name);
923

    
924
  PropertyAttributes attr;
925
  // Get the property.
926
  Handle<Object> result =
927
      Object::GetProperty(object, object, &lookup, name, &attr);
928
  RETURN_IF_EMPTY_HANDLE(isolate(), result);
929
  // If the property is not present, check if we need to throw an
930
  // exception.
931
  if ((lookup.IsInterceptor() || lookup.IsHandler()) &&
932
      attr == ABSENT && IsUndeclaredGlobal(object)) {
933
    return ReferenceError("not_defined", name);
934
  }
935
  return *result;
936
}
937

    
938

    
939
static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
940
                                       Handle<Map> new_receiver_map) {
941
  ASSERT(!new_receiver_map.is_null());
942
  for (int current = 0; current < receiver_maps->length(); ++current) {
943
    if (!receiver_maps->at(current).is_null() &&
944
        receiver_maps->at(current).is_identical_to(new_receiver_map)) {
945
      return false;
946
    }
947
  }
948
  receiver_maps->Add(new_receiver_map);
949
  return true;
950
}
951

    
952

    
953
bool IC::UpdatePolymorphicIC(Handle<HeapObject> receiver,
954
                             Handle<String> name,
955
                             Handle<Code> code) {
956
  if (!code->is_handler()) return false;
957

    
958
  MapHandleList receiver_maps;
959
  CodeHandleList handlers;
960

    
961
  int number_of_valid_maps;
962
  int handler_to_overwrite = -1;
963
  Handle<Map> new_receiver_map(receiver->map());
964
  {
965
    DisallowHeapAllocation no_gc;
966
    target()->FindAllMaps(&receiver_maps);
967
    int number_of_maps = receiver_maps.length();
968
    number_of_valid_maps = number_of_maps;
969

    
970
    for (int i = 0; i < number_of_maps; i++) {
971
      Handle<Map> map = receiver_maps.at(i);
972
      // Filter out deprecated maps to ensure its instances get migrated.
973
      if (map->is_deprecated()) {
974
        number_of_valid_maps--;
975
      // If the receiver map is already in the polymorphic IC, this indicates
976
      // there was a prototoype chain failure. In that case, just overwrite the
977
      // handler.
978
      } else if (map.is_identical_to(new_receiver_map)) {
979
        number_of_valid_maps--;
980
        handler_to_overwrite = i;
981
      }
982
    }
983

    
984
    if (number_of_valid_maps >= 4) return false;
985
    if (number_of_maps == 0) return false;
986

    
987
    if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
988
      return false;
989
    }
990
  }
991

    
992
  number_of_valid_maps++;
993
  if (handler_to_overwrite >= 0) {
994
    handlers.Set(handler_to_overwrite, code);
995
  } else {
996
    receiver_maps.Add(new_receiver_map);
997
    handlers.Add(code);
998
  }
999

    
1000
  Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
1001
      &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode());
1002
  set_target(*ic);
1003
  return true;
1004
}
1005

    
1006

    
1007
void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
1008
                             Handle<Code> handler,
1009
                             Handle<String> name) {
1010
  if (!handler->is_handler()) return set_target(*handler);
1011
  Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
1012
      receiver, handler, name, strict_mode());
1013
  set_target(*ic);
1014
}
1015

    
1016

    
1017
void IC::CopyICToMegamorphicCache(Handle<String> name) {
1018
  MapHandleList receiver_maps;
1019
  CodeHandleList handlers;
1020
  {
1021
    DisallowHeapAllocation no_gc;
1022
    target()->FindAllMaps(&receiver_maps);
1023
    if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
1024
  }
1025
  for (int i = 0; i < receiver_maps.length(); i++) {
1026
    UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
1027
  }
1028
}
1029

    
1030

    
1031
bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
1032
  DisallowHeapAllocation no_allocation;
1033

    
1034
  Map* current_map = target()->FindFirstMap();
1035
  ElementsKind receiver_elements_kind = receiver_map->elements_kind();
1036
  bool more_general_transition =
1037
      IsMoreGeneralElementsKindTransition(
1038
        current_map->elements_kind(), receiver_elements_kind);
1039
  Map* transitioned_map = more_general_transition
1040
      ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
1041
      : NULL;
1042

    
1043
  return transitioned_map == receiver_map;
1044
}
1045

    
1046

    
1047
void IC::PatchCache(Handle<HeapObject> receiver,
1048
                    Handle<String> name,
1049
                    Handle<Code> code) {
1050
  switch (state()) {
1051
    case UNINITIALIZED:
1052
    case PREMONOMORPHIC:
1053
    case MONOMORPHIC_PROTOTYPE_FAILURE:
1054
      UpdateMonomorphicIC(receiver, code, name);
1055
      break;
1056
    case MONOMORPHIC:
1057
      // For now, call stubs are allowed to rewrite to the same stub. This
1058
      // happens e.g., when the field does not contain a function.
1059
      ASSERT(target()->is_call_stub() ||
1060
             target()->is_keyed_call_stub() ||
1061
             !target().is_identical_to(code));
1062
      if (!target()->is_keyed_stub()) {
1063
        bool is_same_handler = false;
1064
        {
1065
          DisallowHeapAllocation no_allocation;
1066
          Code* old_handler = target()->FindFirstHandler();
1067
          is_same_handler = old_handler == *code;
1068
        }
1069
        if (is_same_handler
1070
            && IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
1071
          UpdateMonomorphicIC(receiver, code, name);
1072
          break;
1073
        }
1074
        if (UpdatePolymorphicIC(receiver, name, code)) {
1075
          break;
1076
        }
1077

    
1078
        CopyICToMegamorphicCache(name);
1079
      }
1080

    
1081
      UpdateMegamorphicCache(receiver->map(), *name, *code);
1082
      set_target(*megamorphic_stub());
1083
      break;
1084
    case MEGAMORPHIC:
1085
      UpdateMegamorphicCache(receiver->map(), *name, *code);
1086
      break;
1087
    case POLYMORPHIC:
1088
      if (target()->is_keyed_stub()) {
1089
        // When trying to patch a polymorphic keyed stub with anything other
1090
        // than another polymorphic stub, go generic.
1091
        set_target(*generic_stub());
1092
      } else {
1093
        if (UpdatePolymorphicIC(receiver, name, code)) {
1094
          break;
1095
        }
1096
        CopyICToMegamorphicCache(name);
1097
        UpdateMegamorphicCache(receiver->map(), *name, *code);
1098
        set_target(*megamorphic_stub());
1099
      }
1100
      break;
1101
    case DEBUG_STUB:
1102
      break;
1103
    case GENERIC:
1104
      UNREACHABLE();
1105
      break;
1106
  }
1107
}
1108

    
1109

    
1110
Handle<Code> LoadIC::SimpleFieldLoad(int offset,
1111
                                     bool inobject,
1112
                                     Representation representation) {
1113
  if (kind() == Code::LOAD_IC) {
1114
    LoadFieldStub stub(inobject, offset, representation);
1115
    return stub.GetCode(isolate());
1116
  } else {
1117
    KeyedLoadFieldStub stub(inobject, offset, representation);
1118
    return stub.GetCode(isolate());
1119
  }
1120
}
1121

    
1122
void LoadIC::UpdateCaches(LookupResult* lookup,
1123
                          Handle<Object> object,
1124
                          Handle<String> name) {
1125
  // TODO(verwaest): It would be nice to support loading fields from smis as
1126
  // well. For now just fail to update the cache.
1127
  if (!object->IsHeapObject()) return;
1128

    
1129
  Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1130

    
1131
  Handle<Code> code;
1132
  if (state() == UNINITIALIZED) {
1133
    // This is the first time we execute this inline cache.
1134
    // Set the target to the pre monomorphic stub to delay
1135
    // setting the monomorphic state.
1136
    code = pre_monomorphic_stub();
1137
  } else if (!lookup->IsCacheable()) {
1138
    // Bail out if the result is not cacheable.
1139
    code = slow_stub();
1140
  } else if (object->IsString() &&
1141
             name->Equals(isolate()->heap()->length_string())) {
1142
    int length_index = String::kLengthOffset / kPointerSize;
1143
    code = SimpleFieldLoad(length_index);
1144
  } else if (!object->IsJSObject()) {
1145
    // TODO(jkummerow): It would be nice to support non-JSObjects in
1146
    // ComputeLoadHandler, then we wouldn't need to go generic here.
1147
    code = slow_stub();
1148
  } else if (!lookup->IsProperty()) {
1149
    code = kind() == Code::LOAD_IC
1150
        ? isolate()->stub_cache()->ComputeLoadNonexistent(
1151
              name, Handle<JSObject>::cast(receiver))
1152
        : slow_stub();
1153
  } else {
1154
    code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
1155
  }
1156

    
1157
  PatchCache(receiver, name, code);
1158
  TRACE_IC("LoadIC", name);
1159
}
1160

    
1161

    
1162
void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
1163
  // Cache code holding map should be consistent with
1164
  // GenerateMonomorphicCacheProbe.
1165
  isolate()->stub_cache()->Set(name, map, code);
1166
}
1167

    
1168

    
1169
Handle<Code> IC::ComputeHandler(LookupResult* lookup,
1170
                                Handle<JSObject> receiver,
1171
                                Handle<String> name,
1172
                                Handle<Object> value) {
1173
  Handle<Code> code = isolate()->stub_cache()->FindHandler(
1174
      name, receiver, kind());
1175
  if (!code.is_null()) return code;
1176

    
1177
  code = CompileHandler(lookup, receiver, name, value);
1178

    
1179
  if (code->is_handler() && code->type() != Code::NORMAL) {
1180
    HeapObject::UpdateMapCodeCache(receiver, name, code);
1181
  }
1182

    
1183
  return code;
1184
}
1185

    
1186

    
1187
Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
1188
                                    Handle<JSObject> receiver,
1189
                                    Handle<String> name,
1190
                                    Handle<Object> unused) {
1191
  Handle<JSObject> holder(lookup->holder());
1192
  LoadStubCompiler compiler(isolate(), kind());
1193

    
1194
  switch (lookup->type()) {
1195
    case FIELD: {
1196
      PropertyIndex field = lookup->GetFieldIndex();
1197
      if (receiver.is_identical_to(holder)) {
1198
        return SimpleFieldLoad(field.translate(holder),
1199
                               field.is_inobject(holder),
1200
                               lookup->representation());
1201
      }
1202
      return compiler.CompileLoadField(
1203
          receiver, holder, name, field, lookup->representation());
1204
    }
1205
    case CONSTANT: {
1206
      Handle<Object> constant(lookup->GetConstant(), isolate());
1207
      // TODO(2803): Don't compute a stub for cons strings because they cannot
1208
      // be embedded into code.
1209
      if (constant->IsConsString()) break;
1210
      return compiler.CompileLoadConstant(receiver, holder, name, constant);
1211
    }
1212
    case NORMAL:
1213
      if (kind() != Code::LOAD_IC) break;
1214
      if (holder->IsGlobalObject()) {
1215
        Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
1216
        Handle<PropertyCell> cell(
1217
            global->GetPropertyCell(lookup), isolate());
1218
        // TODO(verwaest): Turn into a handler.
1219
        return isolate()->stub_cache()->ComputeLoadGlobal(
1220
            name, receiver, global, cell, lookup->IsDontDelete());
1221
      }
1222
      // There is only one shared stub for loading normalized
1223
      // properties. It does not traverse the prototype chain, so the
1224
      // property must be found in the receiver for the stub to be
1225
      // applicable.
1226
      if (!holder.is_identical_to(receiver)) break;
1227
      return isolate()->builtins()->LoadIC_Normal();
1228
    case CALLBACKS: {
1229
      // Use simple field loads for some well-known callback properties.
1230
      int object_offset;
1231
      Handle<Map> map(receiver->map());
1232
      if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
1233
        PropertyIndex index =
1234
            PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
1235
        return compiler.CompileLoadField(
1236
            receiver, receiver, name, index, Representation::Tagged());
1237
      }
1238

    
1239
      Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1240
      if (callback->IsExecutableAccessorInfo()) {
1241
        Handle<ExecutableAccessorInfo> info =
1242
            Handle<ExecutableAccessorInfo>::cast(callback);
1243
        if (v8::ToCData<Address>(info->getter()) == 0) break;
1244
        if (!info->IsCompatibleReceiver(*receiver)) break;
1245
        return compiler.CompileLoadCallback(receiver, holder, name, info);
1246
      } else if (callback->IsAccessorPair()) {
1247
        Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
1248
                              isolate());
1249
        if (!getter->IsJSFunction()) break;
1250
        if (holder->IsGlobalObject()) break;
1251
        if (!holder->HasFastProperties()) break;
1252
        Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1253
        CallOptimization call_optimization(function);
1254
        if (call_optimization.is_simple_api_call() &&
1255
            call_optimization.IsCompatibleReceiver(*receiver)) {
1256
          return compiler.CompileLoadCallback(
1257
              receiver, holder, name, call_optimization);
1258
        }
1259
        return compiler.CompileLoadViaGetter(receiver, holder, name, function);
1260
      }
1261
      // TODO(dcarney): Handle correctly.
1262
      if (callback->IsDeclaredAccessorInfo()) break;
1263
      ASSERT(callback->IsForeign());
1264
      // No IC support for old-style native accessors.
1265
      break;
1266
    }
1267
    case INTERCEPTOR:
1268
      ASSERT(HasInterceptorGetter(*holder));
1269
      return compiler.CompileLoadInterceptor(receiver, holder, name);
1270
    default:
1271
      break;
1272
  }
1273

    
1274
  return slow_stub();
1275
}
1276

    
1277

    
1278
static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1279
  // This helper implements a few common fast cases for converting
1280
  // non-smi keys of keyed loads/stores to a smi or a string.
1281
  if (key->IsHeapNumber()) {
1282
    double value = Handle<HeapNumber>::cast(key)->value();
1283
    if (std::isnan(value)) {
1284
      key = isolate->factory()->nan_string();
1285
    } else {
1286
      int int_value = FastD2I(value);
1287
      if (value == int_value && Smi::IsValid(int_value)) {
1288
        key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1289
      }
1290
    }
1291
  } else if (key->IsUndefined()) {
1292
    key = isolate->factory()->undefined_string();
1293
  }
1294
  return key;
1295
}
1296

    
1297

    
1298
Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
1299
  // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1300
  // via megamorphic stubs, since they don't have a map in their relocation info
1301
  // and so the stubs can't be harvested for the object needed for a map check.
1302
  if (target()->type() != Code::NORMAL) {
1303
    TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
1304
    return generic_stub();
1305
  }
1306

    
1307
  Handle<Map> receiver_map(receiver->map(), isolate());
1308
  MapHandleList target_receiver_maps;
1309
  if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
1310
    // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1311
    // yet will do so and stay there.
1312
    return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1313
  }
1314

    
1315
  if (target().is_identical_to(string_stub())) {
1316
    target_receiver_maps.Add(isolate()->factory()->string_map());
1317
  } else {
1318
    target()->FindAllMaps(&target_receiver_maps);
1319
    if (target_receiver_maps.length() == 0) {
1320
      return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1321
    }
1322
  }
1323

    
1324
  // The first time a receiver is seen that is a transitioned version of the
1325
  // previous monomorphic receiver type, assume the new ElementsKind is the
1326
  // monomorphic type. This benefits global arrays that only transition
1327
  // once, and all call sites accessing them are faster if they remain
1328
  // monomorphic. If this optimistic assumption is not true, the IC will
1329
  // miss again and it will become polymorphic and support both the
1330
  // untransitioned and transitioned maps.
1331
  if (state() == MONOMORPHIC &&
1332
      IsMoreGeneralElementsKindTransition(
1333
          target_receiver_maps.at(0)->elements_kind(),
1334
          receiver->GetElementsKind())) {
1335
    return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1336
  }
1337

    
1338
  ASSERT(state() != GENERIC);
1339

    
1340
  // Determine the list of receiver maps that this call site has seen,
1341
  // adding the map that was just encountered.
1342
  if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1343
    // If the miss wasn't due to an unseen map, a polymorphic stub
1344
    // won't help, use the generic stub.
1345
    TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
1346
    return generic_stub();
1347
  }
1348

    
1349
  // If the maximum number of receiver maps has been exceeded, use the generic
1350
  // version of the IC.
1351
  if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1352
    TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
1353
    return generic_stub();
1354
  }
1355

    
1356
  return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
1357
      &target_receiver_maps);
1358
}
1359

    
1360

    
1361
MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
1362
                               Handle<Object> key,
1363
                               ICMissMode miss_mode) {
1364
  if (MigrateDeprecated(object)) {
1365
    return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1366
  }
1367

    
1368
  MaybeObject* maybe_object = NULL;
1369
  Handle<Code> stub = generic_stub();
1370

    
1371
  // Check for values that can be converted into an internalized string directly
1372
  // or is representable as a smi.
1373
  key = TryConvertKey(key, isolate());
1374

    
1375
  if (key->IsInternalizedString()) {
1376
    maybe_object = LoadIC::Load(object, Handle<String>::cast(key));
1377
    if (maybe_object->IsFailure()) return maybe_object;
1378
  } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1379
    ASSERT(!object->IsJSGlobalProxy());
1380
    if (miss_mode != MISS_FORCE_GENERIC) {
1381
      if (object->IsString() && key->IsNumber()) {
1382
        if (state() == UNINITIALIZED) stub = string_stub();
1383
      } else if (object->IsJSObject()) {
1384
        Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1385
        if (receiver->elements()->map() ==
1386
            isolate()->heap()->non_strict_arguments_elements_map()) {
1387
          stub = non_strict_arguments_stub();
1388
        } else if (receiver->HasIndexedInterceptor()) {
1389
          stub = indexed_interceptor_stub();
1390
        } else if (!key->ToSmi()->IsFailure() &&
1391
                   (!target().is_identical_to(non_strict_arguments_stub()))) {
1392
          stub = LoadElementStub(receiver);
1393
        }
1394
      }
1395
    }
1396
  }
1397

    
1398
  if (!is_target_set()) {
1399
    if (*stub == *generic_stub()) {
1400
      TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1401
    }
1402
    ASSERT(!stub.is_null());
1403
    set_target(*stub);
1404
    TRACE_IC("LoadIC", key);
1405
  }
1406

    
1407
  if (maybe_object != NULL) return maybe_object;
1408
  return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1409
}
1410

    
1411

    
1412
static bool LookupForWrite(Handle<JSObject> receiver,
1413
                           Handle<String> name,
1414
                           Handle<Object> value,
1415
                           LookupResult* lookup,
1416
                           IC* ic) {
1417
  Handle<JSObject> holder = receiver;
1418
  receiver->Lookup(*name, lookup);
1419
  if (lookup->IsFound()) {
1420
    if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
1421

    
1422
    if (lookup->holder() == *receiver) {
1423
      if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) {
1424
        receiver->LocalLookupRealNamedProperty(*name, lookup);
1425
        return lookup->IsFound() &&
1426
            !lookup->IsReadOnly() &&
1427
            lookup->CanHoldValue(value) &&
1428
            lookup->IsCacheable();
1429
      }
1430
      return lookup->CanHoldValue(value);
1431
    }
1432

    
1433
    if (lookup->IsPropertyCallbacks()) return true;
1434

    
1435
    // Currently normal holders in the prototype chain are not supported. They
1436
    // would require a runtime positive lookup and verification that the details
1437
    // have not changed.
1438
    if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
1439
    holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
1440
  }
1441

    
1442
  // While normally LookupTransition gets passed the receiver, in this case we
1443
  // pass the holder of the property that we overwrite. This keeps the holder in
1444
  // the LookupResult intact so we can later use it to generate a prototype
1445
  // chain check. This avoids a double lookup, but requires us to pass in the
1446
  // receiver when trying to fetch extra information from the transition.
1447
  receiver->map()->LookupTransition(*holder, *name, lookup);
1448
  if (!lookup->IsTransition()) return false;
1449
  PropertyDetails target_details =
1450
      lookup->GetTransitionDetails(receiver->map());
1451
  if (target_details.IsReadOnly()) return false;
1452

    
1453
  // If the value that's being stored does not fit in the field that the
1454
  // instance would transition to, create a new transition that fits the value.
1455
  // This has to be done before generating the IC, since that IC will embed the
1456
  // transition target.
1457
  // Ensure the instance and its map were migrated before trying to update the
1458
  // transition target.
1459
  ASSERT(!receiver->map()->is_deprecated());
1460
  if (!value->FitsRepresentation(target_details.representation())) {
1461
    Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
1462
    Map::GeneralizeRepresentation(
1463
        target, target->LastAdded(),
1464
        value->OptimalRepresentation(), FORCE_FIELD);
1465
    // Lookup the transition again since the transition tree may have changed
1466
    // entirely by the migration above.
1467
    receiver->map()->LookupTransition(*holder, *name, lookup);
1468
    if (!lookup->IsTransition()) return false;
1469
    ic->MarkMonomorphicPrototypeFailure();
1470
  }
1471
  return true;
1472
}
1473

    
1474

    
1475
MaybeObject* StoreIC::Store(Handle<Object> object,
1476
                            Handle<String> name,
1477
                            Handle<Object> value,
1478
                            JSReceiver::StoreFromKeyed store_mode) {
1479
  if (MigrateDeprecated(object) || object->IsJSProxy()) {
1480
    Handle<Object> result = JSReceiver::SetProperty(
1481
        Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode());
1482
    RETURN_IF_EMPTY_HANDLE(isolate(), result);
1483
    return *result;
1484
  }
1485

    
1486
  // If the object is undefined or null it's illegal to try to set any
1487
  // properties on it; throw a TypeError in that case.
1488
  if (object->IsUndefined() || object->IsNull()) {
1489
    return TypeError("non_object_property_store", object, name);
1490
  }
1491

    
1492
  // The length property of string values is read-only. Throw in strict mode.
1493
  if (strict_mode() == kStrictMode && object->IsString() &&
1494
      name->Equals(isolate()->heap()->length_string())) {
1495
    return TypeError("strict_read_only_property", object, name);
1496
  }
1497

    
1498
  // Ignore other stores where the receiver is not a JSObject.
1499
  // TODO(1475): Must check prototype chains of object wrappers.
1500
  if (!object->IsJSObject()) return *value;
1501

    
1502
  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1503

    
1504
  // Check if the given name is an array index.
1505
  uint32_t index;
1506
  if (name->AsArrayIndex(&index)) {
1507
    Handle<Object> result =
1508
        JSObject::SetElement(receiver, index, value, NONE, strict_mode());
1509
    RETURN_IF_EMPTY_HANDLE(isolate(), result);
1510
    return *value;
1511
  }
1512

    
1513
  // Observed objects are always modified through the runtime.
1514
  if (FLAG_harmony_observation && receiver->map()->is_observed()) {
1515
    Handle<Object> result = JSReceiver::SetProperty(
1516
        receiver, name, value, NONE, strict_mode(), store_mode);
1517
    RETURN_IF_EMPTY_HANDLE(isolate(), result);
1518
    return *result;
1519
  }
1520

    
1521
  // Use specialized code for setting the length of arrays with fast
1522
  // properties. Slow properties might indicate redefinition of the length
1523
  // property. Note that when redefined using Object.freeze, it's possible
1524
  // to have fast properties but a read-only length.
1525
  if (FLAG_use_ic &&
1526
      receiver->IsJSArray() &&
1527
      name->Equals(isolate()->heap()->length_string()) &&
1528
      Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
1529
      receiver->HasFastProperties() &&
1530
      !receiver->map()->is_frozen()) {
1531
    Handle<Code> stub =
1532
        StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate());
1533
    set_target(*stub);
1534
    TRACE_IC("StoreIC", name);
1535
    Handle<Object> result = JSReceiver::SetProperty(
1536
        receiver, name, value, NONE, strict_mode(), store_mode);
1537
    RETURN_IF_EMPTY_HANDLE(isolate(), result);
1538
    return *result;
1539
  }
1540

    
1541
  if (receiver->IsJSGlobalProxy()) {
1542
    if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) {
1543
      // Generate a generic stub that goes to the runtime when we see a global
1544
      // proxy as receiver.
1545
      Handle<Code> stub = global_proxy_stub();
1546
      set_target(*stub);
1547
      TRACE_IC("StoreIC", name);
1548
    }
1549
    Handle<Object> result = JSReceiver::SetProperty(
1550
        receiver, name, value, NONE, strict_mode(), store_mode);
1551
    RETURN_IF_EMPTY_HANDLE(isolate(), result);
1552
    return *result;
1553
  }
1554

    
1555
  LookupResult lookup(isolate());
1556
  bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
1557
  if (!can_store &&
1558
      strict_mode() == kStrictMode &&
1559
      !(lookup.IsProperty() && lookup.IsReadOnly()) &&
1560
      IsUndeclaredGlobal(object)) {
1561
    // Strict mode doesn't allow setting non-existent global property.
1562
    return ReferenceError("not_defined", name);
1563
  }
1564
  if (FLAG_use_ic) {
1565
    if (state() == UNINITIALIZED) {
1566
      Handle<Code> stub = pre_monomorphic_stub();
1567
      set_target(*stub);
1568
      TRACE_IC("StoreIC", name);
1569
    } else if (can_store) {
1570
      UpdateCaches(&lookup, receiver, name, value);
1571
    } else if (!name->IsCacheable(isolate()) ||
1572
               lookup.IsNormal() ||
1573
               (lookup.IsField() && lookup.CanHoldValue(value))) {
1574
      Handle<Code> stub = generic_stub();
1575
      set_target(*stub);
1576
    }
1577
  }
1578

    
1579
  // Set the property.
1580
  Handle<Object> result = JSReceiver::SetProperty(
1581
      receiver, name, value, NONE, strict_mode(), store_mode);
1582
  RETURN_IF_EMPTY_HANDLE(isolate(), result);
1583
  return *result;
1584
}
1585

    
1586

    
1587
void StoreIC::UpdateCaches(LookupResult* lookup,
1588
                           Handle<JSObject> receiver,
1589
                           Handle<String> name,
1590
                           Handle<Object> value) {
1591
  ASSERT(!receiver->IsJSGlobalProxy());
1592
  ASSERT(lookup->IsFound());
1593

    
1594
  // These are not cacheable, so we never see such LookupResults here.
1595
  ASSERT(!lookup->IsHandler());
1596

    
1597
  Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
1598

    
1599
  PatchCache(receiver, name, code);
1600
  TRACE_IC("StoreIC", name);
1601
}
1602

    
1603

    
1604
Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
1605
                                     Handle<JSObject> receiver,
1606
                                     Handle<String> name,
1607
                                     Handle<Object> value) {
1608
  Handle<JSObject> holder(lookup->holder());
1609
  StoreStubCompiler compiler(isolate(), strict_mode(), kind());
1610
  switch (lookup->type()) {
1611
    case FIELD:
1612
      return compiler.CompileStoreField(receiver, lookup, name);
1613
    case TRANSITION: {
1614
      // Explicitly pass in the receiver map since LookupForWrite may have
1615
      // stored something else than the receiver in the holder.
1616
      Handle<Map> transition(
1617
          lookup->GetTransitionTarget(receiver->map()), isolate());
1618
      int descriptor = transition->LastAdded();
1619

    
1620
      DescriptorArray* target_descriptors = transition->instance_descriptors();
1621
      PropertyDetails details = target_descriptors->GetDetails(descriptor);
1622

    
1623
      if (details.type() == CALLBACKS || details.attributes() != NONE) break;
1624

    
1625
      return compiler.CompileStoreTransition(
1626
          receiver, lookup, transition, name);
1627
    }
1628
    case NORMAL:
1629
      if (kind() == Code::KEYED_STORE_IC) break;
1630
      if (receiver->IsGlobalObject()) {
1631
        // The stub generated for the global object picks the value directly
1632
        // from the property cell. So the property must be directly on the
1633
        // global object.
1634
        Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1635
        Handle<PropertyCell> cell(
1636
            global->GetPropertyCell(lookup), isolate());
1637
        // TODO(verwaest): Turn into a handler.
1638
        return isolate()->stub_cache()->ComputeStoreGlobal(
1639
            name, global, cell, value, strict_mode());
1640
      }
1641
      ASSERT(holder.is_identical_to(receiver));
1642
      return strict_mode() == kStrictMode
1643
          ? isolate()->builtins()->StoreIC_Normal_Strict()
1644
          : isolate()->builtins()->StoreIC_Normal();
1645
    case CALLBACKS: {
1646
      if (kind() == Code::KEYED_STORE_IC) break;
1647
      Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1648
      if (callback->IsExecutableAccessorInfo()) {
1649
        Handle<ExecutableAccessorInfo> info =
1650
            Handle<ExecutableAccessorInfo>::cast(callback);
1651
        if (v8::ToCData<Address>(info->setter()) == 0) break;
1652
        if (!holder->HasFastProperties()) break;
1653
        if (!info->IsCompatibleReceiver(*receiver)) break;
1654
        return compiler.CompileStoreCallback(receiver, holder, name, info);
1655
      } else if (callback->IsAccessorPair()) {
1656
        Handle<Object> setter(
1657
            Handle<AccessorPair>::cast(callback)->setter(), isolate());
1658
        if (!setter->IsJSFunction()) break;
1659
        if (holder->IsGlobalObject()) break;
1660
        if (!holder->HasFastProperties()) break;
1661
        Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1662
        CallOptimization call_optimization(function);
1663
        if (call_optimization.is_simple_api_call() &&
1664
            call_optimization.IsCompatibleReceiver(*receiver)) {
1665
          return compiler.CompileStoreCallback(
1666
              receiver, holder, name, call_optimization);
1667
        }
1668
        return compiler.CompileStoreViaSetter(
1669
            receiver, holder, name, Handle<JSFunction>::cast(setter));
1670
      }
1671
      // TODO(dcarney): Handle correctly.
1672
      if (callback->IsDeclaredAccessorInfo()) break;
1673
      ASSERT(callback->IsForeign());
1674
      // No IC support for old-style native accessors.
1675
      break;
1676
    }
1677
    case INTERCEPTOR:
1678
      if (kind() == Code::KEYED_STORE_IC) break;
1679
      ASSERT(HasInterceptorSetter(*receiver));
1680
      return compiler.CompileStoreInterceptor(receiver, name);
1681
    case CONSTANT:
1682
      break;
1683
    case NONEXISTENT:
1684
    case HANDLER:
1685
      UNREACHABLE();
1686
      break;
1687
  }
1688
  return slow_stub();
1689
}
1690

    
1691

    
1692
Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1693
                                            KeyedAccessStoreMode store_mode) {
1694
  // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1695
  // via megamorphic stubs, since they don't have a map in their relocation info
1696
  // and so the stubs can't be harvested for the object needed for a map check.
1697
  if (target()->type() != Code::NORMAL) {
1698
    TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
1699
    return generic_stub();
1700
  }
1701

    
1702
  Handle<Map> receiver_map(receiver->map(), isolate());
1703
  if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
1704
    // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1705
    // yet will do so and stay there.
1706
    Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
1707
    store_mode = GetNonTransitioningStoreMode(store_mode);
1708
    return isolate()->stub_cache()->ComputeKeyedStoreElement(
1709
        monomorphic_map, strict_mode(), store_mode);
1710
  }
1711

    
1712
  MapHandleList target_receiver_maps;
1713
  target()->FindAllMaps(&target_receiver_maps);
1714
  if (target_receiver_maps.length() == 0) {
1715
    // In the case that there is a non-map-specific IC is installed (e.g. keyed
1716
    // stores into properties in dictionary mode), then there will be not
1717
    // receiver maps in the target.
1718
    return generic_stub();
1719
  }
1720

    
1721
  // There are several special cases where an IC that is MONOMORPHIC can still
1722
  // transition to a different GetNonTransitioningStoreMode IC that handles a
1723
  // superset of the original IC. Handle those here if the receiver map hasn't
1724
  // changed or it has transitioned to a more general kind.
1725
  KeyedAccessStoreMode old_store_mode =
1726
      Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
1727
  Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1728
  if (state() == MONOMORPHIC) {
1729
      // If the "old" and "new" maps are in the same elements map family, stay
1730
      // MONOMORPHIC and use the map for the most generic ElementsKind.
1731
    Handle<Map> transitioned_receiver_map = receiver_map;
1732
    if (IsTransitionStoreMode(store_mode)) {
1733
      transitioned_receiver_map =
1734
          ComputeTransitionedMap(receiver, store_mode);
1735
    }
1736
    if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
1737
      // Element family is the same, use the "worst" case map.
1738
      store_mode = GetNonTransitioningStoreMode(store_mode);
1739
      return isolate()->stub_cache()->ComputeKeyedStoreElement(
1740
          transitioned_receiver_map, strict_mode(), store_mode);
1741
    } else if (*previous_receiver_map == receiver->map() &&
1742
               old_store_mode == STANDARD_STORE &&
1743
               (IsGrowStoreMode(store_mode) ||
1744
                store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1745
                store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1746
      // A "normal" IC that handles stores can switch to a version that can
1747
      // grow at the end of the array, handle OOB accesses or copy COW arrays
1748
      // and still stay MONOMORPHIC.
1749
      return isolate()->stub_cache()->ComputeKeyedStoreElement(
1750
          receiver_map, strict_mode(), store_mode);
1751
    }
1752
  }
1753

    
1754
  ASSERT(state() != GENERIC);
1755

    
1756
  bool map_added =
1757
      AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1758

    
1759
  if (IsTransitionStoreMode(store_mode)) {
1760
    Handle<Map> transitioned_receiver_map =
1761
        ComputeTransitionedMap(receiver, store_mode);
1762
    map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1763
                                            transitioned_receiver_map);
1764
  }
1765

    
1766
  if (!map_added) {
1767
    // If the miss wasn't due to an unseen map, a polymorphic stub
1768
    // won't help, use the generic stub.
1769
    TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
1770
    return generic_stub();
1771
  }
1772

    
1773
  // If the maximum number of receiver maps has been exceeded, use the generic
1774
  // version of the IC.
1775
  if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1776
    TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
1777
    return generic_stub();
1778
  }
1779

    
1780
  // Make sure all polymorphic handlers have the same store mode, otherwise the
1781
  // generic stub must be used.
1782
  store_mode = GetNonTransitioningStoreMode(store_mode);
1783
  if (old_store_mode != STANDARD_STORE) {
1784
    if (store_mode == STANDARD_STORE) {
1785
      store_mode = old_store_mode;
1786
    } else if (store_mode != old_store_mode) {
1787
      TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
1788
      return generic_stub();
1789
    }
1790
  }
1791

    
1792
  // If the store mode isn't the standard mode, make sure that all polymorphic
1793
  // receivers are either external arrays, or all "normal" arrays. Otherwise,
1794
  // use the generic stub.
1795
  if (store_mode != STANDARD_STORE) {
1796
    int external_arrays = 0;
1797
    for (int i = 0; i < target_receiver_maps.length(); ++i) {
1798
      if (target_receiver_maps[i]->has_external_array_elements()) {
1799
        external_arrays++;
1800
      }
1801
    }
1802
    if (external_arrays != 0 &&
1803
        external_arrays != target_receiver_maps.length()) {
1804
      TRACE_GENERIC_IC(isolate(), "KeyedIC",
1805
          "unsupported combination of external and normal arrays");
1806
      return generic_stub();
1807
    }
1808
  }
1809

    
1810
  return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
1811
      &target_receiver_maps, store_mode, strict_mode());
1812
}
1813

    
1814

    
1815
Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1816
    Handle<JSObject> receiver,
1817
    KeyedAccessStoreMode store_mode) {
1818
  switch (store_mode) {
1819
    case STORE_TRANSITION_SMI_TO_OBJECT:
1820
    case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1821
    case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1822
    case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1823
      return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
1824
    case STORE_TRANSITION_SMI_TO_DOUBLE:
1825
    case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1826
      return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
1827
    case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1828
    case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1829
    case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1830
    case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1831
      return JSObject::GetElementsTransitionMap(receiver,
1832
                                                FAST_HOLEY_ELEMENTS);
1833
    case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1834
    case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1835
      return JSObject::GetElementsTransitionMap(receiver,
1836
                                                FAST_HOLEY_DOUBLE_ELEMENTS);
1837
    case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1838
      ASSERT(receiver->map()->has_external_array_elements());
1839
      // Fall through
1840
    case STORE_NO_TRANSITION_HANDLE_COW:
1841
    case STANDARD_STORE:
1842
    case STORE_AND_GROW_NO_TRANSITION:
1843
      return Handle<Map>(receiver->map(), isolate());
1844
  }
1845
  return Handle<Map>::null();
1846
}
1847

    
1848

    
1849
bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
1850
                         int index) {
1851
  if (receiver->IsJSArray()) {
1852
    return JSArray::cast(*receiver)->length()->IsSmi() &&
1853
        index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1854
  }
1855
  return index >= receiver->elements()->length();
1856
}
1857

    
1858

    
1859
KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1860
                                                Handle<Object> key,
1861
                                                Handle<Object> value) {
1862
  ASSERT(!key->ToSmi()->IsFailure());
1863
  Smi* smi_key = NULL;
1864
  key->ToSmi()->To(&smi_key);
1865
  int index = smi_key->value();
1866
  bool oob_access = IsOutOfBoundsAccess(receiver, index);
1867
  bool allow_growth = receiver->IsJSArray() && oob_access;
1868
  if (allow_growth) {
1869
    // Handle growing array in stub if necessary.
1870
    if (receiver->HasFastSmiElements()) {
1871
      if (value->IsHeapNumber()) {
1872
        if (receiver->HasFastHoleyElements()) {
1873
          return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1874
        } else {
1875
          return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1876
        }
1877
      }
1878
      if (value->IsHeapObject()) {
1879
        if (receiver->HasFastHoleyElements()) {
1880
          return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1881
        } else {
1882
          return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
1883
        }
1884
      }
1885
    } else if (receiver->HasFastDoubleElements()) {
1886
      if (!value->IsSmi() && !value->IsHeapNumber()) {
1887
        if (receiver->HasFastHoleyElements()) {
1888
          return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1889
        } else {
1890
          return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1891
        }
1892
      }
1893
    }
1894
    return STORE_AND_GROW_NO_TRANSITION;
1895
  } else {
1896
    // Handle only in-bounds elements accesses.
1897
    if (receiver->HasFastSmiElements()) {
1898
      if (value->IsHeapNumber()) {
1899
        if (receiver->HasFastHoleyElements()) {
1900
          return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1901
        } else {
1902
          return STORE_TRANSITION_SMI_TO_DOUBLE;
1903
        }
1904
      } else if (value->IsHeapObject()) {
1905
        if (receiver->HasFastHoleyElements()) {
1906
          return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1907
        } else {
1908
          return STORE_TRANSITION_SMI_TO_OBJECT;
1909
        }
1910
      }
1911
    } else if (receiver->HasFastDoubleElements()) {
1912
      if (!value->IsSmi() && !value->IsHeapNumber()) {
1913
        if (receiver->HasFastHoleyElements()) {
1914
          return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1915
        } else {
1916
          return STORE_TRANSITION_DOUBLE_TO_OBJECT;
1917
        }
1918
      }
1919
    }
1920
    if (!FLAG_trace_external_array_abuse &&
1921
        receiver->map()->has_external_array_elements() && oob_access) {
1922
      return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1923
    }
1924
    Heap* heap = receiver->GetHeap();
1925
    if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
1926
      return STORE_NO_TRANSITION_HANDLE_COW;
1927
    } else {
1928
      return STANDARD_STORE;
1929
    }
1930
  }
1931
}
1932

    
1933

    
1934
MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
1935
                                 Handle<Object> key,
1936
                                 Handle<Object> value,
1937
                                 ICMissMode miss_mode) {
1938
  if (MigrateDeprecated(object)) {
1939
    return Runtime::SetObjectPropertyOrFail(
1940
        isolate(), object , key, value, NONE, strict_mode());
1941
  }
1942

    
1943
  // Check for values that can be converted into an internalized string directly
1944
  // or is representable as a smi.
1945
  key = TryConvertKey(key, isolate());
1946

    
1947
  MaybeObject* maybe_object = NULL;
1948
  Handle<Code> stub = generic_stub();
1949

    
1950
  if (key->IsInternalizedString()) {
1951
    maybe_object = StoreIC::Store(object,
1952
                                  Handle<String>::cast(key),
1953
                                  value,
1954
                                  JSReceiver::MAY_BE_STORE_FROM_KEYED);
1955
    if (maybe_object->IsFailure()) return maybe_object;
1956
  } else {
1957
    bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1958
        !(FLAG_harmony_observation && object->IsJSObject() &&
1959
          JSObject::cast(*object)->map()->is_observed());
1960
    if (use_ic && !object->IsSmi()) {
1961
      // Don't use ICs for maps of the objects in Array's prototype chain. We
1962
      // expect to be able to trap element sets to objects with those maps in
1963
      // the runtime to enable optimization of element hole access.
1964
      Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
1965
      if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
1966
    }
1967

    
1968
    if (use_ic) {
1969
      ASSERT(!object->IsJSGlobalProxy());
1970

    
1971
      if (miss_mode != MISS_FORCE_GENERIC) {
1972
        if (object->IsJSObject()) {
1973
          Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1974
          bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
1975
          if (receiver->elements()->map() ==
1976
              isolate()->heap()->non_strict_arguments_elements_map()) {
1977
            stub = non_strict_arguments_stub();
1978
          } else if (key_is_smi_like &&
1979
                     (!target().is_identical_to(non_strict_arguments_stub()))) {
1980
            KeyedAccessStoreMode store_mode =
1981
                GetStoreMode(receiver, key, value);
1982
            stub = StoreElementStub(receiver, store_mode);
1983
          }
1984
        }
1985
      }
1986
    }
1987
  }
1988

    
1989
  if (!is_target_set()) {
1990
    if (*stub == *generic_stub()) {
1991
      TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
1992
    }
1993
    ASSERT(!stub.is_null());
1994
    set_target(*stub);
1995
    TRACE_IC("StoreIC", key);
1996
  }
1997

    
1998
  if (maybe_object) return maybe_object;
1999
  return Runtime::SetObjectPropertyOrFail(
2000
      isolate(), object , key, value, NONE, strict_mode());
2001
}
2002

    
2003

    
2004
#undef TRACE_IC
2005

    
2006

    
2007
// ----------------------------------------------------------------------------
2008
// Static IC stub generators.
2009
//
2010

    
2011
// Used from ic-<arch>.cc.
2012
RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
2013
  HandleScope scope(isolate);
2014
  ASSERT(args.length() == 2);
2015
  CallIC ic(isolate);
2016
  Handle<Object> receiver = args.at<Object>(0);
2017
  Handle<String> key = args.at<String>(1);
2018
  ic.UpdateState(receiver, key);
2019
  MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
2020
  JSFunction* raw_function;
2021
  if (!maybe_result->To(&raw_function)) return maybe_result;
2022

    
2023
  // The first time the inline cache is updated may be the first time the
2024
  // function it references gets called. If the function is lazily compiled
2025
  // then the first call will trigger a compilation. We check for this case
2026
  // and we do the compilation immediately, instead of waiting for the stub
2027
  // currently attached to the JSFunction object to trigger compilation.
2028
  if (raw_function->is_compiled()) return raw_function;
2029

    
2030
  Handle<JSFunction> function(raw_function);
2031
  JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2032
  return *function;
2033
}
2034

    
2035

    
2036
// Used from ic-<arch>.cc.
2037
RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
2038
  HandleScope scope(isolate);
2039
  ASSERT(args.length() == 2);
2040
  KeyedCallIC ic(isolate);
2041
  Handle<Object> receiver = args.at<Object>(0);
2042
  Handle<Object> key = args.at<Object>(1);
2043
  ic.UpdateState(receiver, key);
2044
  MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
2045
  // Result could be a function or a failure.
2046
  JSFunction* raw_function = NULL;
2047
  if (!maybe_result->To(&raw_function)) return maybe_result;
2048

    
2049
  if (raw_function->is_compiled()) return raw_function;
2050

    
2051
  Handle<JSFunction> function(raw_function, isolate);
2052
  JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2053
  return *function;
2054
}
2055

    
2056

    
2057
// Used from ic-<arch>.cc.
2058
RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
2059
  HandleScope scope(isolate);
2060
  ASSERT(args.length() == 2);
2061
  LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2062
  Handle<Object> receiver = args.at<Object>(0);
2063
  Handle<String> key = args.at<String>(1);
2064
  ic.UpdateState(receiver, key);
2065
  return ic.Load(receiver, key);
2066
}
2067

    
2068

    
2069
// Used from ic-<arch>.cc
2070
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
2071
  HandleScope scope(isolate);
2072
  ASSERT(args.length() == 2);
2073
  KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2074
  Handle<Object> receiver = args.at<Object>(0);
2075
  Handle<Object> key = args.at<Object>(1);
2076
  ic.UpdateState(receiver, key);
2077
  return ic.Load(receiver, key, MISS);
2078
}
2079

    
2080

    
2081
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) {
2082
  HandleScope scope(isolate);
2083
  ASSERT(args.length() == 2);
2084
  KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2085
  Handle<Object> receiver = args.at<Object>(0);
2086
  Handle<Object> key = args.at<Object>(1);
2087
  ic.UpdateState(receiver, key);
2088
  return ic.Load(receiver, key, MISS);
2089
}
2090

    
2091

    
2092
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
2093
  HandleScope scope(isolate);
2094
  ASSERT(args.length() == 2);
2095
  KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2096
  Handle<Object> receiver = args.at<Object>(0);
2097
  Handle<Object> key = args.at<Object>(1);
2098
  ic.UpdateState(receiver, key);
2099
  return ic.Load(receiver, key, MISS_FORCE_GENERIC);
2100
}
2101

    
2102

    
2103
// Used from ic-<arch>.cc.
2104
RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
2105
  HandleScope scope(isolate);
2106
  ASSERT(args.length() == 3);
2107
  StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2108
  Handle<Object> receiver = args.at<Object>(0);
2109
  Handle<String> key = args.at<String>(1);
2110
  ic.UpdateState(receiver, key);
2111
  return ic.Store(receiver, key, args.at<Object>(2));
2112
}
2113

    
2114

    
2115
RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
2116
  HandleScope scope(isolate);
2117
  ASSERT(args.length() == 3);
2118
  StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2119
  Handle<Object> receiver = args.at<Object>(0);
2120
  Handle<String> key = args.at<String>(1);
2121
  ic.UpdateState(receiver, key);
2122
  return ic.Store(receiver, key, args.at<Object>(2));
2123
}
2124

    
2125

    
2126
RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
2127
  SealHandleScope shs(isolate);
2128

    
2129
  ASSERT(args.length() == 2);
2130
  JSArray* receiver = JSArray::cast(args[0]);
2131
  Object* len = args[1];
2132

    
2133
  // The generated code should filter out non-Smis before we get here.
2134
  ASSERT(len->IsSmi());
2135

    
2136
#ifdef DEBUG
2137
  // The length property has to be a writable callback property.
2138
  LookupResult debug_lookup(isolate);
2139
  receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup);
2140
  ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly());
2141
#endif
2142

    
2143
  Object* result;
2144
  MaybeObject* maybe_result = receiver->SetElementsLength(len);
2145
  if (!maybe_result->To(&result)) return maybe_result;
2146

    
2147
  return len;
2148
}
2149

    
2150

    
2151
// Extend storage is called in a store inline cache when
2152
// it is necessary to extend the properties array of a
2153
// JSObject.
2154
RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
2155
  SealHandleScope shs(isolate);
2156
  ASSERT(args.length() == 3);
2157

    
2158
  // Convert the parameters
2159
  JSObject* object = JSObject::cast(args[0]);
2160
  Map* transition = Map::cast(args[1]);
2161
  Object* value = args[2];
2162

    
2163
  // Check the object has run out out property space.
2164
  ASSERT(object->HasFastProperties());
2165
  ASSERT(object->map()->unused_property_fields() == 0);
2166

    
2167
  // Expand the properties array.
2168
  FixedArray* old_storage = object->properties();
2169
  int new_unused = transition->unused_property_fields();
2170
  int new_size = old_storage->length() + new_unused + 1;
2171
  Object* result;
2172
  MaybeObject* maybe_result = old_storage->CopySize(new_size);
2173
  if (!maybe_result->ToObject(&result)) return maybe_result;
2174

    
2175
  FixedArray* new_storage = FixedArray::cast(result);
2176

    
2177
  Object* to_store = value;
2178

    
2179
  if (FLAG_track_double_fields) {
2180
    DescriptorArray* descriptors = transition->instance_descriptors();
2181
    PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
2182
    if (details.representation().IsDouble()) {
2183
      MaybeObject* maybe_storage =
2184
          isolate->heap()->AllocateHeapNumber(value->Number());
2185
      if (!maybe_storage->To(&to_store)) return maybe_storage;
2186
    }
2187
  }
2188

    
2189
  new_storage->set(old_storage->length(), to_store);
2190

    
2191
  // Set the new property value and do the map transition.
2192
  object->set_properties(new_storage);
2193
  object->set_map(transition);
2194

    
2195
  // Return the stored value.
2196
  return value;
2197
}
2198

    
2199

    
2200
// Used from ic-<arch>.cc.
2201
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
2202
  HandleScope scope(isolate);
2203
  ASSERT(args.length() == 3);
2204
  KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2205
  Handle<Object> receiver = args.at<Object>(0);
2206
  Handle<Object> key = args.at<Object>(1);
2207
  ic.UpdateState(receiver, key);
2208
  return ic.Store(receiver, key, args.at<Object>(2), MISS);
2209
}
2210

    
2211

    
2212
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) {
2213
  HandleScope scope(isolate);
2214
  ASSERT(args.length() == 3);
2215
  KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2216
  Handle<Object> receiver = args.at<Object>(0);
2217
  Handle<Object> key = args.at<Object>(1);
2218
  ic.UpdateState(receiver, key);
2219
  return ic.Store(receiver, key, args.at<Object>(2), MISS);
2220
}
2221

    
2222

    
2223
RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) {
2224
  HandleScope scope(isolate);
2225
  ASSERT(args.length() == 3);
2226
  StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2227
  Handle<Object> object = args.at<Object>(0);
2228
  Handle<Object> key = args.at<Object>(1);
2229
  Handle<Object> value = args.at<Object>(2);
2230
  StrictModeFlag strict_mode = ic.strict_mode();
2231
  return Runtime::SetObjectProperty(isolate,
2232
                                    object,
2233
                                    key,
2234
                                    value,
2235
                                    NONE,
2236
                                    strict_mode);
2237
}
2238

    
2239

    
2240
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
2241
  HandleScope scope(isolate);
2242
  ASSERT(args.length() == 3);
2243
  KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2244
  Handle<Object> object = args.at<Object>(0);
2245
  Handle<Object> key = args.at<Object>(1);
2246
  Handle<Object> value = args.at<Object>(2);
2247
  StrictModeFlag strict_mode = ic.strict_mode();
2248
  return Runtime::SetObjectProperty(isolate,
2249
                                    object,
2250
                                    key,
2251
                                    value,
2252
                                    NONE,
2253
                                    strict_mode);
2254
}
2255

    
2256

    
2257
RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
2258
  HandleScope scope(isolate);
2259
  ASSERT(args.length() == 3);
2260
  KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2261
  Handle<Object> receiver = args.at<Object>(0);
2262
  Handle<Object> key = args.at<Object>(1);
2263
  ic.UpdateState(receiver, key);
2264
  return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC);
2265
}
2266

    
2267

    
2268
RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
2269
  HandleScope scope(isolate);
2270
  ASSERT(args.length() == 4);
2271
  KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2272
  Handle<Object> value = args.at<Object>(0);
2273
  Handle<Object> key = args.at<Object>(2);
2274
  Handle<Object> object = args.at<Object>(3);
2275
  StrictModeFlag strict_mode = ic.strict_mode();
2276
  return Runtime::SetObjectProperty(isolate,
2277
                                    object,
2278
                                    key,
2279
                                    value,
2280
                                    NONE,
2281
                                    strict_mode);
2282
}
2283

    
2284

    
2285
const char* BinaryOpIC::GetName(TypeInfo type_info) {
2286
  switch (type_info) {
2287
    case UNINITIALIZED: return "Uninitialized";
2288
    case SMI: return "Smi";
2289
    case INT32: return "Int32";
2290
    case NUMBER: return "Number";
2291
    case ODDBALL: return "Oddball";
2292
    case STRING: return "String";
2293
    case GENERIC: return "Generic";
2294
    default: return "Invalid";
2295
  }
2296
}
2297

    
2298

    
2299
MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
2300
  Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2301
  BinaryOpStub stub(extra_ic_state);
2302

    
2303
  Handle<Type> left_type = stub.GetLeftType(isolate());
2304
  Handle<Type> right_type = stub.GetRightType(isolate());
2305
  bool smi_was_enabled = left_type->Maybe(Type::Smi()) &&
2306
                         right_type->Maybe(Type::Smi());
2307

    
2308
  Maybe<Handle<Object> > result = stub.Result(left, right, isolate());
2309
  if (!result.has_value) return Failure::Exception();
2310

    
2311
#ifdef DEBUG
2312
  if (FLAG_trace_ic) {
2313
    char buffer[100];
2314
    NoAllocationStringAllocator allocator(buffer,
2315
                                        static_cast<unsigned>(sizeof(buffer)));
2316
    StringStream stream(&allocator);
2317
    stream.Add("[");
2318
    stub.PrintName(&stream);
2319

    
2320
    stub.UpdateStatus(left, right, result);
2321

    
2322
    stream.Add(" => ");
2323
    stub.PrintState(&stream);
2324
    stream.Add(" ");
2325
    stream.OutputToStdOut();
2326
    PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate())));
2327
    JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2328
    PrintF("]\n");
2329
  } else {
2330
    stub.UpdateStatus(left, right, result);
2331
  }
2332
#else
2333
  stub.UpdateStatus(left, right, result);
2334
#endif
2335

    
2336
  Handle<Code> code = stub.GetCode(isolate());
2337
  set_target(*code);
2338

    
2339
  left_type = stub.GetLeftType(isolate());
2340
  right_type = stub.GetRightType(isolate());
2341
  bool enable_smi = left_type->Maybe(Type::Smi()) &&
2342
                    right_type->Maybe(Type::Smi());
2343

    
2344
  if (!smi_was_enabled && enable_smi) {
2345
    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2346
  } else if (smi_was_enabled && !enable_smi) {
2347
    PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2348
  }
2349

    
2350
  ASSERT(result.has_value);
2351
  return static_cast<MaybeObject*>(*result.value);
2352
}
2353

    
2354

    
2355
RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
2356
  HandleScope scope(isolate);
2357
  Handle<Object> left = args.at<Object>(0);
2358
  Handle<Object> right = args.at<Object>(1);
2359
  BinaryOpIC ic(isolate);
2360
  return ic.Transition(left, right);
2361
}
2362

    
2363

    
2364
Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2365
  ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
2366
  Code* code = NULL;
2367
  CHECK(stub.FindCodeInCache(&code, isolate));
2368
  return code;
2369
}
2370

    
2371

    
2372
Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
2373
  ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
2374
  return stub.GetCode(isolate);
2375
}
2376

    
2377

    
2378
const char* CompareIC::GetStateName(State state) {
2379
  switch (state) {
2380
    case UNINITIALIZED: return "UNINITIALIZED";
2381
    case SMI: return "SMI";
2382
    case NUMBER: return "NUMBER";
2383
    case INTERNALIZED_STRING: return "INTERNALIZED_STRING";
2384
    case STRING: return "STRING";
2385
    case UNIQUE_NAME: return "UNIQUE_NAME";
2386
    case OBJECT: return "OBJECT";
2387
    case KNOWN_OBJECT: return "KNOWN_OBJECT";
2388
    case GENERIC: return "GENERIC";
2389
  }
2390
  UNREACHABLE();
2391
  return NULL;
2392
}
2393

    
2394

    
2395
Handle<Type> CompareIC::StateToType(
2396
    Isolate* isolate,
2397
    CompareIC::State state,
2398
    Handle<Map> map) {
2399
  switch (state) {
2400
    case CompareIC::UNINITIALIZED:
2401
      return handle(Type::None(), isolate);
2402
    case CompareIC::SMI:
2403
      return handle(Type::Smi(), isolate);
2404
    case CompareIC::NUMBER:
2405
      return handle(Type::Number(), isolate);
2406
    case CompareIC::STRING:
2407
      return handle(Type::String(), isolate);
2408
    case CompareIC::INTERNALIZED_STRING:
2409
      return handle(Type::InternalizedString(), isolate);
2410
    case CompareIC::UNIQUE_NAME:
2411
      return handle(Type::UniqueName(), isolate);
2412
    case CompareIC::OBJECT:
2413
      return handle(Type::Receiver(), isolate);
2414
    case CompareIC::KNOWN_OBJECT:
2415
      return handle(
2416
          map.is_null() ? Type::Receiver() : Type::Class(map), isolate);
2417
    case CompareIC::GENERIC:
2418
      return handle(Type::Any(), isolate);
2419
  }
2420
  UNREACHABLE();
2421
  return Handle<Type>();
2422
}
2423

    
2424

    
2425
void CompareIC::StubInfoToType(int stub_minor_key,
2426
                               Handle<Type>* left_type,
2427
                               Handle<Type>* right_type,
2428
                               Handle<Type>* overall_type,
2429
                               Handle<Map> map,
2430
                               Isolate* isolate) {
2431
  State left_state, right_state, handler_state;
2432
  ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
2433
                                &handler_state, NULL);
2434
  *left_type = StateToType(isolate, left_state);
2435
  *right_type = StateToType(isolate, right_state);
2436
  *overall_type = StateToType(isolate, handler_state, map);
2437
}
2438

    
2439

    
2440
CompareIC::State CompareIC::NewInputState(State old_state,
2441
                                          Handle<Object> value) {
2442
  switch (old_state) {
2443
    case UNINITIALIZED:
2444
      if (value->IsSmi()) return SMI;
2445
      if (value->IsHeapNumber()) return NUMBER;
2446
      if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2447
      if (value->IsString()) return STRING;
2448
      if (value->IsSymbol()) return UNIQUE_NAME;
2449
      if (value->IsJSObject()) return OBJECT;
2450
      break;
2451
    case SMI:
2452
      if (value->IsSmi()) return SMI;
2453
      if (value->IsHeapNumber()) return NUMBER;
2454
      break;
2455
    case NUMBER:
2456
      if (value->IsNumber()) return NUMBER;
2457
      break;
2458
    case INTERNALIZED_STRING:
2459
      if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2460
      if (value->IsString()) return STRING;
2461
      if (value->IsSymbol()) return UNIQUE_NAME;
2462
      break;
2463
    case STRING:
2464
      if (value->IsString()) return STRING;
2465
      break;
2466
    case UNIQUE_NAME:
2467
      if (value->IsUniqueName()) return UNIQUE_NAME;
2468
      break;
2469
    case OBJECT:
2470
      if (value->IsJSObject()) return OBJECT;
2471
      break;
2472
    case GENERIC:
2473
      break;
2474
    case KNOWN_OBJECT:
2475
      UNREACHABLE();
2476
      break;
2477
  }
2478
  return GENERIC;
2479
}
2480

    
2481

    
2482
CompareIC::State CompareIC::TargetState(State old_state,
2483
                                        State old_left,
2484
                                        State old_right,
2485
                                        bool has_inlined_smi_code,
2486
                                        Handle<Object> x,
2487
                                        Handle<Object> y) {
2488
  switch (old_state) {
2489
    case UNINITIALIZED:
2490
      if (x->IsSmi() && y->IsSmi()) return SMI;
2491
      if (x->IsNumber() && y->IsNumber()) return NUMBER;
2492
      if (Token::IsOrderedRelationalCompareOp(op_)) {
2493
        // Ordered comparisons treat undefined as NaN, so the
2494
        // NUMBER stub will do the right thing.
2495
        if ((x->IsNumber() && y->IsUndefined()) ||
2496
            (y->IsNumber() && x->IsUndefined())) {
2497
          return NUMBER;
2498
        }
2499
      }
2500
      if (x->IsInternalizedString() && y->IsInternalizedString()) {
2501
        // We compare internalized strings as plain ones if we need to determine
2502
        // the order in a non-equality compare.
2503
        return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING;
2504
      }
2505
      if (x->IsString() && y->IsString()) return STRING;
2506
      if (!Token::IsEqualityOp(op_)) return GENERIC;
2507
      if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2508
      if (x->IsJSObject() && y->IsJSObject()) {
2509
        if (Handle<JSObject>::cast(x)->map() ==
2510
            Handle<JSObject>::cast(y)->map()) {
2511
          return KNOWN_OBJECT;
2512
        } else {
2513
          return OBJECT;
2514
        }
2515
      }
2516
      return GENERIC;
2517
    case SMI:
2518
      return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
2519
    case INTERNALIZED_STRING:
2520
      ASSERT(Token::IsEqualityOp(op_));
2521
      if (x->IsString() && y->IsString()) return STRING;
2522
      if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2523
      return GENERIC;
2524
    case NUMBER:
2525
      // If the failure was due to one side changing from smi to heap number,
2526
      // then keep the state (if other changed at the same time, we will get
2527
      // a second miss and then go to generic).
2528
      if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
2529
      if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
2530
      return GENERIC;
2531
    case KNOWN_OBJECT:
2532
      ASSERT(Token::IsEqualityOp(op_));
2533
      if (x->IsJSObject() && y->IsJSObject()) return OBJECT;
2534
      return GENERIC;
2535
    case STRING:
2536
    case UNIQUE_NAME:
2537
    case OBJECT:
2538
    case GENERIC:
2539
      return GENERIC;
2540
  }
2541
  UNREACHABLE();
2542
  return GENERIC;  // Make the compiler happy.
2543
}
2544

    
2545

    
2546
void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2547
  HandleScope scope(isolate());
2548
  State previous_left, previous_right, previous_state;
2549
  ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
2550
                                &previous_right, &previous_state, NULL);
2551
  State new_left = NewInputState(previous_left, x);
2552
  State new_right = NewInputState(previous_right, y);
2553
  State state = TargetState(previous_state, previous_left, previous_right,
2554
                            HasInlinedSmiCode(address()), x, y);
2555
  ICCompareStub stub(op_, new_left, new_right, state);
2556
  if (state == KNOWN_OBJECT) {
2557
    stub.set_known_map(
2558
        Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2559
  }
2560
  set_target(*stub.GetCode(isolate()));
2561

    
2562
#ifdef DEBUG
2563
  if (FLAG_trace_ic) {
2564
    PrintF("[CompareIC in ");
2565
    JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2566
    PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2567
           GetStateName(previous_left),
2568
           GetStateName(previous_right),
2569
           GetStateName(previous_state),
2570
           GetStateName(new_left),
2571
           GetStateName(new_right),
2572
           GetStateName(state),
2573
           Token::Name(op_),
2574
           static_cast<void*>(*stub.GetCode(isolate())));
2575
  }
2576
#endif
2577

    
2578
  // Activate inlined smi code.
2579
  if (previous_state == UNINITIALIZED) {
2580
    PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2581
  }
2582
}
2583

    
2584

    
2585
// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc.
2586
RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
2587
  HandleScope scope(isolate);
2588
  ASSERT(args.length() == 3);
2589
  CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2590
  ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2591
  return ic.raw_target();
2592
}
2593

    
2594

    
2595
void CompareNilIC::Clear(Address address, Code* target) {
2596
  if (IsCleared(target)) return;
2597
  Code::ExtraICState state = target->extended_extra_ic_state();
2598

    
2599
  CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED);
2600
  stub.ClearState();
2601

    
2602
  Code* code = NULL;
2603
  CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
2604

    
2605
  SetTargetAtAddress(address, code);
2606
}
2607

    
2608

    
2609
MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil,
2610
                                            Handle<Object> object) {
2611
  if (object->IsNull() || object->IsUndefined()) {
2612
    return Smi::FromInt(true);
2613
  }
2614
  return Smi::FromInt(object->IsUndetectableObject());
2615
}
2616

    
2617

    
2618
MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
2619
  Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2620

    
2621
  CompareNilICStub stub(extra_ic_state);
2622

    
2623
  // Extract the current supported types from the patched IC and calculate what
2624
  // types must be supported as a result of the miss.
2625
  bool already_monomorphic = stub.IsMonomorphic();
2626

    
2627
  stub.UpdateStatus(object);
2628

    
2629
  NilValue nil = stub.GetNilValue();
2630

    
2631
  // Find or create the specialized stub to support the new set of types.
2632
  Handle<Code> code;
2633
  if (stub.IsMonomorphic()) {
2634
    Handle<Map> monomorphic_map(already_monomorphic
2635
                                ? target()->FindFirstMap()
2636
                                : HeapObject::cast(*object)->map());
2637
    code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
2638
  } else {
2639
    code = stub.GetCode(isolate());
2640
  }
2641
  set_target(*code);
2642
  return DoCompareNilSlow(nil, object);
2643
}
2644

    
2645

    
2646
RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) {
2647
  HandleScope scope(isolate);
2648
  Handle<Object> object = args.at<Object>(0);
2649
  CompareNilIC ic(isolate);
2650
  return ic.CompareNil(object);
2651
}
2652

    
2653

    
2654
RUNTIME_FUNCTION(MaybeObject*, Unreachable) {
2655
  UNREACHABLE();
2656
  CHECK(false);
2657
  return isolate->heap()->undefined_value();
2658
}
2659

    
2660

    
2661
Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2662
  switch (op) {
2663
    default:
2664
      UNREACHABLE();
2665
    case Token::ADD:
2666
      return Builtins::ADD;
2667
      break;
2668
    case Token::SUB:
2669
      return Builtins::SUB;
2670
      break;
2671
    case Token::MUL:
2672
      return Builtins::MUL;
2673
      break;
2674
    case Token::DIV:
2675
      return Builtins::DIV;
2676
      break;
2677
    case Token::MOD:
2678
      return Builtins::MOD;
2679
      break;
2680
    case Token::BIT_OR:
2681
      return Builtins::BIT_OR;
2682
      break;
2683
    case Token::BIT_AND:
2684
      return Builtins::BIT_AND;
2685
      break;
2686
    case Token::BIT_XOR:
2687
      return Builtins::BIT_XOR;
2688
      break;
2689
    case Token::SAR:
2690
      return Builtins::SAR;
2691
      break;
2692
    case Token::SHR:
2693
      return Builtins::SHR;
2694
      break;
2695
    case Token::SHL:
2696
      return Builtins::SHL;
2697
      break;
2698
  }
2699
}
2700

    
2701

    
2702
MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
2703
                                    Code::ExtraICState extra_ic_state) {
2704
  ToBooleanStub stub(extra_ic_state);
2705
  bool to_boolean_value = stub.UpdateStatus(object);
2706
  Handle<Code> code = stub.GetCode(isolate());
2707
  set_target(*code);
2708
  return Smi::FromInt(to_boolean_value ? 1 : 0);
2709
}
2710

    
2711

    
2712
RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
2713
  ASSERT(args.length() == 1);
2714
  HandleScope scope(isolate);
2715
  Handle<Object> object = args.at<Object>(0);
2716
  ToBooleanIC ic(isolate);
2717
  Code::ExtraICState extra_ic_state = ic.target()->extended_extra_ic_state();
2718
  return ic.ToBoolean(object, extra_ic_state);
2719
}
2720

    
2721

    
2722
static const Address IC_utilities[] = {
2723
#define ADDR(name) FUNCTION_ADDR(name),
2724
    IC_UTIL_LIST(ADDR)
2725
    NULL
2726
#undef ADDR
2727
};
2728

    
2729

    
2730
Address IC::AddressFromUtilityId(IC::UtilityId id) {
2731
  return IC_utilities[id];
2732
}
2733

    
2734

    
2735
} }  // namespace v8::internal