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

#ifndef V8_STUB_CACHE_H_
#define V8_STUB_CACHE_H_

31
#include "allocation.h"
32
#include "arguments.h"
33
#include "code-stubs.h"
34
#include "ic-inl.h"
35
#include "macro-assembler.h"
danno@chromium.org's avatar
danno@chromium.org committed
36
#include "objects.h"
37
#include "zone-inl.h"
38

39 40
namespace v8 {
namespace internal {
41 42 43 44 45 46 47 48 49 50


// The stub cache is used for megamorphic calls and property accesses.
// It maps (map, name, type)->Code*

// The design of the table uses the inline cache stubs used for
// mono-morphic calls. The beauty of this, we do not have to
// invalidate the cache whenever a prototype map is changed.  The stub
// validates the map chain as in the mono-morphic case.

51 52

class CallOptimization;
53
class SmallMapList;
54 55
class StubCache;

56

57 58 59 60 61 62 63 64 65 66 67
class SCTableReference {
 public:
  Address address() const { return address_; }

 private:
  explicit SCTableReference(Address address) : address_(address) {}

  Address address_;

  friend class StubCache;
};
68

69

70
class StubCache {
71 72
 public:
  struct Entry {
73
    Name* key;
74
    Code* value;
75
    Map* map;
76 77
  };

78
  void Initialize();
79

80 81 82
  Handle<JSObject> StubHolder(Handle<JSObject> receiver,
                              Handle<JSObject> holder);

83 84 85 86 87
  Handle<Code> FindIC(Handle<Name> name,
                      Handle<Map> stub_holder_map,
                      Code::Kind kind,
                      Code::ExtraICState extra_state = Code::kNoExtraICState);

88 89 90
  Handle<Code> FindIC(Handle<Name> name,
                      Handle<JSObject> stub_holder,
                      Code::Kind kind,
91
                      Code::ExtraICState extra_state = Code::kNoExtraICState);
92

93 94 95 96
  Handle<Code> FindHandler(Handle<Name> name,
                           Handle<JSObject> receiver,
                           Code::Kind kind,
                           StrictModeFlag strict_mode = kNonStrictMode);
97

98 99 100 101
  Handle<Code> ComputeMonomorphicIC(Handle<HeapObject> receiver,
                                    Handle<Code> handler,
                                    Handle<Name> name,
                                    StrictModeFlag strict_mode);
102 103 104

  // Computes the right stub matching. Inserts the result in the
  // cache before returning.  This might compile a stub if needed.
105
  Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
106
                                      Handle<JSObject> object);
107 108 109

  // ---

110 111 112 113
  Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);

  Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
                                        StrictModeFlag strict_mode,
114
                                        KeyedAccessStoreMode store_mode);
115

116 117 118
  Handle<Code> ComputeCallField(int argc,
                                Code::Kind,
                                Code::ExtraICState extra_state,
119
                                Handle<Name> name,
120 121
                                Handle<Object> object,
                                Handle<JSObject> holder,
122
                                PropertyIndex index);
123

124 125 126
  Handle<Code> ComputeCallConstant(int argc,
                                   Code::Kind,
                                   Code::ExtraICState extra_state,
127
                                   Handle<Name> name,
128 129 130
                                   Handle<Object> object,
                                   Handle<JSObject> holder,
                                   Handle<JSFunction> function);
131

132 133 134
  Handle<Code> ComputeCallInterceptor(int argc,
                                      Code::Kind,
                                      Code::ExtraICState extra_state,
135
                                      Handle<Name> name,
136 137
                                      Handle<Object> object,
                                      Handle<JSObject> holder);
138

139 140 141
  Handle<Code> ComputeCallGlobal(int argc,
                                 Code::Kind,
                                 Code::ExtraICState extra_state,
142
                                 Handle<Name> name,
143
                                 Handle<JSObject> object,
144
                                 Handle<GlobalObject> holder,
145
                                 Handle<PropertyCell> cell,
146
                                 Handle<JSFunction> function);
147

148
  // ---
149

150
  Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
151

152
  Handle<Code> ComputeKeyedCallInitialize(int argc);
153

154 155 156 157 158 159 160
  Handle<Code> ComputeCallPreMonomorphic(int argc,
                                         Code::Kind kind,
                                         Code::ExtraICState extra_state);

  Handle<Code> ComputeCallNormal(int argc,
                                 Code::Kind kind,
                                 Code::ExtraICState state);
161

162
  Handle<Code> ComputeCallArguments(int argc);
163

164 165 166
  Handle<Code> ComputeCallMegamorphic(int argc,
                                      Code::Kind kind,
                                      Code::ExtraICState state);
167

168 169 170
  Handle<Code> ComputeCallMiss(int argc,
                               Code::Kind kind,
                               Code::ExtraICState state);
171

172 173
  // ---

174
  Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
175
                                 CompareNilICStub& stub);
176 177 178

  // ---

179 180
  Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
  Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
181
                                              KeyedAccessStoreMode store_mode,
182 183
                                              StrictModeFlag strict_mode);

184 185 186 187 188
  Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
                                    CodeHandleList* handlers,
                                    int number_of_valid_maps,
                                    Handle<Name> name,
                                    StrictModeFlag strict_mode);
189

190
  // Finds the Code object stored in the Heap::non_monomorphic_cache().
191
  Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
192

193
#ifdef ENABLE_DEBUGGER_SUPPORT
194
  Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
195

196
  Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
197
#endif
198 199

  // Update cache for entry hash(name, map).
200
  Code* Set(Name* name, Map* map, Code* code);
201 202

  // Clear the lookup table (@ mark compact collection).
203
  void Clear();
204

205
  // Collect all maps that match the name and flags.
206
  void CollectMatchingMaps(SmallMapList* types,
207
                           Handle<Name> name,
208
                           Code::Flags flags,
209
                           Handle<Context> native_context,
210
                           Zone* zone);
211

212
  // Generate code for probing the stub cache table.
213
  // Arguments extra, extra2 and extra3 may be used to pass additional scratch
214
  // registers. Set to no_reg if not needed.
215 216 217 218 219 220
  void GenerateProbe(MacroAssembler* masm,
                     Code::Flags flags,
                     Register receiver,
                     Register name,
                     Register scratch,
                     Register extra,
221 222
                     Register extra2 = no_reg,
                     Register extra3 = no_reg);
223 224 225 226 227 228

  enum Table {
    kPrimary,
    kSecondary
  };

229 230 231 232 233 234 235

  SCTableReference key_reference(StubCache::Table table) {
    return SCTableReference(
        reinterpret_cast<Address>(&first_entry(table)->key));
  }


236 237 238 239 240 241
  SCTableReference map_reference(StubCache::Table table) {
    return SCTableReference(
        reinterpret_cast<Address>(&first_entry(table)->map));
  }


242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  SCTableReference value_reference(StubCache::Table table) {
    return SCTableReference(
        reinterpret_cast<Address>(&first_entry(table)->value));
  }


  StubCache::Entry* first_entry(StubCache::Table table) {
    switch (table) {
      case StubCache::kPrimary: return StubCache::primary_;
      case StubCache::kSecondary: return StubCache::secondary_;
    }
    UNREACHABLE();
    return NULL;
  }

257
  Isolate* isolate() { return isolate_; }
ager@chromium.org's avatar
ager@chromium.org committed
258
  Heap* heap() { return isolate()->heap(); }
259
  Factory* factory() { return isolate()->factory(); }
260

261 262 263 264 265 266 267 268 269 270
  // These constants describe the structure of the interceptor arguments on the
  // stack. The arguments are pushed by the (platform-specific)
  // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
  // LoadWithInterceptor.
  static const int kInterceptorArgsNameIndex = 0;
  static const int kInterceptorArgsInfoIndex = 1;
  static const int kInterceptorArgsThisIndex = 2;
  static const int kInterceptorArgsHolderIndex = 3;
  static const int kInterceptorArgsLength = 4;

271
 private:
272
  explicit StubCache(Isolate* isolate);
273

274 275 276
  Handle<Code> ComputeCallInitialize(int argc,
                                     RelocInfo::Mode mode,
                                     Code::Kind kind);
277

278 279 280 281 282 283 284 285 286 287
  // The stub cache has a primary and secondary level.  The two levels have
  // different hashing algorithms in order to avoid simultaneous collisions
  // in both caches.  Unlike a probing strategy (quadratic or otherwise) the
  // update strategy on updates is fairly clear and simple:  Any existing entry
  // in the primary cache is moved to the secondary cache, and secondary cache
  // entries are overwritten.

  // Hash algorithm for the primary table.  This algorithm is replicated in
  // assembler for every architecture.  Returns an index into the table that
  // is scaled by 1 << kHeapObjectTagSize.
288
  static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
289 290 291 292
    // This works well because the heap object tag size and the hash
    // shift are equal.  Shifting down the length field to get the
    // hash code would effectively throw away two bits of the hash
    // code.
293
    STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
294
    // Compute the hash of the name (use entire hash field).
295
    ASSERT(name->HasHashCode());
296
    uint32_t field = name->hash_field();
297 298 299 300 301
    // Using only the low bits in 64-bit mode is unlikely to increase the
    // risk of collision even if the heap is spread over an area larger than
    // 4Gb (and not at all if it isn't).
    uint32_t map_low32bits =
        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
302 303 304 305
    // We always set the in_loop bit to zero when generating the lookup code
    // so do it here too so the hash codes match.
    uint32_t iflags =
        (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
306
    // Base the offset on a simple combination of name, flags, and map.
307
    uint32_t key = (map_low32bits + field) ^ iflags;
308 309 310
    return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
  }

311 312 313
  // Hash algorithm for the secondary table.  This algorithm is replicated in
  // assembler for every architecture.  Returns an index into the table that
  // is scaled by 1 << kHeapObjectTagSize.
314
  static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
315
    // Use the seed from the primary cache in the secondary cache.
316
    uint32_t name_low32bits =
317
        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
318 319 320 321
    // We always set the in_loop bit to zero when generating the lookup code
    // so do it here too so the hash codes match.
    uint32_t iflags =
        (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
322
    uint32_t key = (seed - name_low32bits) + iflags;
323 324 325 326
    return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
  }

  // Compute the entry for a given offset in exactly the same way as
327
  // we do in generated code.  We generate an hash code that already
328
  // ends in Name::kHashShift 0s.  Then we multiply it so it is a multiple
329 330
  // of sizeof(Entry).  This makes it easier to avoid making mistakes
  // in the hashed offset computations.
331
  static Entry* entry(Entry* table, int offset) {
332
    const int multiplier = sizeof(*table) >> Name::kHashShift;
333
    return reinterpret_cast<Entry*>(
334
        reinterpret_cast<Address>(table) + offset * multiplier);
335
  }
336

337 338 339 340
  static const int kPrimaryTableBits = 11;
  static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
  static const int kSecondaryTableBits = 9;
  static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
341 342 343

  Entry primary_[kPrimaryTableSize];
  Entry secondary_[kSecondaryTableSize];
344
  Isolate* isolate_;
345

346 347 348
  friend class Isolate;
  friend class SCTableReference;

349
  DISALLOW_COPY_AND_ASSIGN(StubCache);
350
};
351

352

353 354 355 356
// ------------------------------------------------------------------------


// Support functions for IC stubs for callbacks.
357
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty);
358 359 360


// Support functions for IC stubs for interceptors.
361 362 363 364 365 366
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
367 368


369 370 371 372
enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
enum IcCheckType { ELEMENT, PROPERTY };


373
// The stub compilers compile stubs for the stub cache.
374 375
class StubCompiler BASE_EMBEDDED {
 public:
376 377
  explicit StubCompiler(Isolate* isolate)
      : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { }
378

379 380
  // Functions to compile either CallIC or KeyedCallIC.  The specific kind
  // is extracted from the code flags.
381 382 383 384 385 386
  Handle<Code> CompileCallInitialize(Code::Flags flags);
  Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
  Handle<Code> CompileCallNormal(Code::Flags flags);
  Handle<Code> CompileCallMegamorphic(Code::Flags flags);
  Handle<Code> CompileCallArguments(Code::Flags flags);
  Handle<Code> CompileCallMiss(Code::Flags flags);
387

388
#ifdef ENABLE_DEBUGGER_SUPPORT
389 390
  Handle<Code> CompileCallDebugBreak(Code::Flags flags);
  Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags);
391
#endif
392 393 394 395 396

  // Static functions for generating parts of stubs.
  static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
                                                  int index,
                                                  Register prototype);
397

398 399 400 401 402 403 404 405 406 407 408 409
  // Helper function used to check that the dictionary doesn't contain
  // the property. This function may return false negatives, so miss_label
  // must always call a backup property check that is complete.
  // This function is safe to call if the receiver has fast properties.
  // Name must be unique and receiver must be a heap object.
  static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
                                               Label* miss_label,
                                               Register receiver,
                                               Handle<Name> name,
                                               Register r0,
                                               Register r1);

410
  // Generates prototype loading code that uses the objects from the
411 412 413 414 415
  // context we were in when this function was called. If the context
  // has changed, a jump to miss is performed. This ties the generated
  // code to a particular context and so must not be used in cases
  // where the generated code is not allowed to have references to
  // objects from a context.
416 417
  static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
                                                        int index,
418 419
                                                        Register prototype,
                                                        Label* miss);
420

421
  static void GenerateFastPropertyLoad(MacroAssembler* masm,
422 423
                                       Register dst,
                                       Register src,
424 425 426
                                       bool inobject,
                                       int index,
                                       Representation representation);
427

428 429 430 431
  static void GenerateLoadArrayLength(MacroAssembler* masm,
                                      Register receiver,
                                      Register scratch,
                                      Label* miss_label);
432

433
  static void GenerateLoadStringLength(MacroAssembler* masm,
434 435 436
                                       Register receiver,
                                       Register scratch1,
                                       Register scratch2,
437
                                       Label* miss_label);
438

439 440 441 442 443
  static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
                                            Register receiver,
                                            Register scratch1,
                                            Register scratch2,
                                            Label* miss_label);
444

445 446 447 448
  // Generate code to check that a global property cell is empty. Create
  // the property cell at compilation time if no cell exists for the
  // property.
  static void GenerateCheckPropertyCell(MacroAssembler* masm,
449
                                        Handle<JSGlobalObject> global,
450 451 452 453 454 455 456 457 458 459 460 461 462
                                        Handle<Name> name,
                                        Register scratch,
                                        Label* miss);

  // Calls GenerateCheckPropertyCell for each global object in the prototype
  // chain from object to (but not including) holder.
  static void GenerateCheckPropertyCells(MacroAssembler* masm,
                                         Handle<JSObject> object,
                                         Handle<JSObject> holder,
                                         Handle<Name> name,
                                         Register scratch,
                                         Label* miss);

463
  static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
464

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
  // Generates code that verifies that the property holder has not changed
  // (checking maps of objects in the prototype chain for fast and global
  // objects or doing negative lookup for slow objects, ensures that the
  // property cells for global objects are still empty) and checks that the map
  // of the holder has not changed. If necessary the function also generates
  // code for security check in case of global object holders. Helps to make
  // sure that the current IC is still valid.
  //
  // The scratch and holder registers are always clobbered, but the object
  // register is only clobbered if it the same as the holder register. The
  // function returns a register containing the holder - either object_reg or
  // holder_reg.
  // The function can optionally (when save_at_depth !=
  // kInvalidProtoDepth) save the object at the given depth by moving
  // it to [esp + kPointerSize].
480 481 482 483 484 485
  Register CheckPrototypes(Handle<JSObject> object,
                           Register object_reg,
                           Handle<JSObject> holder,
                           Register holder_reg,
                           Register scratch1,
                           Register scratch2,
486
                           Handle<Name> name,
487 488
                           Label* miss,
                           PrototypeCheckType check = CHECK_ALL_MAPS) {
489
    return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
490
                           scratch2, name, kInvalidProtoDepth, miss, check);
491
  }
492

493 494 495 496 497 498
  Register CheckPrototypes(Handle<JSObject> object,
                           Register object_reg,
                           Handle<JSObject> holder,
                           Register holder_reg,
                           Register scratch1,
                           Register scratch2,
499
                           Handle<Name> name,
500
                           int save_at_depth,
501 502
                           Label* miss,
                           PrototypeCheckType check = CHECK_ALL_MAPS);
503

504

505
 protected:
506
  Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
507
  Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
508

509 510 511
  MacroAssembler* masm() { return &masm_; }
  void set_failure(Failure* failure) { failure_ = failure; }

512
  static void LookupPostInterceptor(Handle<JSObject> holder,
513
                                    Handle<Name> name,
514 515
                                    LookupResult* lookup);

516
  Isolate* isolate() { return isolate_; }
517 518
  Heap* heap() { return isolate()->heap(); }
  Factory* factory() { return isolate()->factory(); }
519

520
  static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
521

522
 private:
523
  Isolate* isolate_;
524
  MacroAssembler masm_;
525
  Failure* failure_;
526 527 528
};


529 530 531
enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };


532
class BaseLoadStoreStubCompiler: public StubCompiler {
533
 public:
534 535 536 537
  BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind)
      : StubCompiler(isolate), kind_(kind) {
    InitializeRegisters();
  }
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
  virtual ~BaseLoadStoreStubCompiler() { }

  Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
                                    Handle<Code> handler,
                                    Handle<Name> name);

  Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
                                    CodeHandleList* handlers,
                                    Handle<Name> name,
                                    Code::StubType type,
                                    IcCheckType check);

  virtual void GenerateNameCheck(Handle<Name> name,
                                 Register name_reg,
                                 Label* miss) { }

  static Builtins::Name MissBuiltin(Code::Kind kind) {
    switch (kind) {
      case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
      case Code::STORE_IC: return Builtins::kStoreIC_Miss;
      case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
      case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
      default: UNREACHABLE();
    }
    return Builtins::kLoadIC_Miss;
  }

 protected:
  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
                                         Register object_reg,
                                         Handle<JSObject> holder,
                                         Handle<Name> name,
                                         Label* miss) = 0;

  virtual void HandlerFrontendFooter(Handle<Name> name,
                                     Label* success,
                                     Label* miss) = 0;

  Register HandlerFrontend(Handle<JSObject> object,
                           Register object_reg,
                           Handle<JSObject> holder,
                           Handle<Name> name,
                           Label* success);

582 583 584 585
  Handle<Code> GetCode(Code::Kind kind,
                       Code::StubType type,
                       Handle<Name> name);

586 587 588 589
  Handle<Code> GetICCode(Code::Kind kind,
                         Code::StubType type,
                         Handle<Name> name,
                         InlineCacheState state = MONOMORPHIC);
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
  Code::Kind kind() { return kind_; }

  Logger::LogEventsAndTags log_kind(Handle<Code> code) {
    if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
    if (kind_ == Code::LOAD_IC) {
      return code->ic_state() == MONOMORPHIC
          ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
    } else if (kind_ == Code::KEYED_LOAD_IC) {
      return code->ic_state() == MONOMORPHIC
          ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
    } else if (kind_ == Code::STORE_IC) {
      return code->ic_state() == MONOMORPHIC
          ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG;
    } else {
      return code->ic_state() == MONOMORPHIC
          ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG;
    }
  }
  void JitEvent(Handle<Name> name, Handle<Code> code);
609 610 611 612 613 614 615 616

  virtual Code::ExtraICState extra_state() { return Code::kNoExtraICState; }
  virtual Register receiver() = 0;
  virtual Register name() = 0;
  virtual Register scratch1() = 0;
  virtual Register scratch2() = 0;
  virtual Register scratch3() = 0;

617 618 619
  void InitializeRegisters();

  Code::Kind kind_;
620 621 622 623
  Register* registers_;
};


624
class LoadStubCompiler: public BaseLoadStoreStubCompiler {
625
 public:
626 627 628
  LoadStubCompiler(Isolate* isolate, Code::Kind kind = Code::LOAD_IC)
      : BaseLoadStoreStubCompiler(isolate, kind) { }
  virtual ~LoadStubCompiler() { }
629 630 631

  Handle<Code> CompileLoadField(Handle<JSObject> object,
                                Handle<JSObject> holder,
632
                                Handle<Name> name,
633 634
                                PropertyIndex index,
                                Representation representation);
635

636
  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
637
                                   Handle<JSObject> holder,
638
                                   Handle<Name> name,
639
                                   Handle<ExecutableAccessorInfo> callback);
640

641 642 643 644 645
  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
                                   Handle<JSObject> holder,
                                   Handle<Name> name,
                                   const CallOptimization& call_optimization);

646 647
  Handle<Code> CompileLoadConstant(Handle<JSObject> object,
                                   Handle<JSObject> holder,
648
                                   Handle<Name> name,
649
                                   Handle<Object> value);
650 651 652

  Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
                                      Handle<JSObject> holder,
653
                                      Handle<Name> name);
654

655 656 657 658 659 660 661 662 663 664 665 666
  Handle<Code> CompileLoadViaGetter(Handle<JSObject> object,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
                                    Handle<JSFunction> getter);

  static void GenerateLoadViaGetter(MacroAssembler* masm,
                                    Register receiver,
                                    Handle<JSFunction> getter);

  Handle<Code> CompileLoadNonexistent(Handle<JSObject> object,
                                      Handle<JSObject> last,
                                      Handle<Name> name,
667
                                      Handle<JSGlobalObject> global);
668 669 670 671 672 673 674 675 676

  Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
                                 Handle<GlobalObject> holder,
                                 Handle<PropertyCell> cell,
                                 Handle<Name> name,
                                 bool is_dont_delete);

  static Register* registers();

677
 protected:
678 679 680 681 682 683 684 685 686
  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
                                         Register object_reg,
                                         Handle<JSObject> holder,
                                         Handle<Name> name,
                                         Label* miss);

  virtual void HandlerFrontendFooter(Handle<Name> name,
                                     Label* success,
                                     Label* miss);
687 688 689 690

  Register CallbackHandlerFrontend(Handle<JSObject> object,
                                   Register object_reg,
                                   Handle<JSObject> holder,
691
                                   Handle<Name> name,
692
                                   Label* success,
693
                                   Handle<Object> callback);
694 695
  void NonexistentHandlerFrontend(Handle<JSObject> object,
                                  Handle<JSObject> last,
696
                                  Handle<Name> name,
697
                                  Label* success,
698
                                  Handle<JSGlobalObject> global);
699 700 701

  void GenerateLoadField(Register reg,
                         Handle<JSObject> holder,
702 703
                         PropertyIndex field,
                         Representation representation);
704
  void GenerateLoadConstant(Handle<Object> value);
705 706
  void GenerateLoadCallback(Register reg,
                            Handle<ExecutableAccessorInfo> callback);
707
  void GenerateLoadCallback(const CallOptimization& call_optimization);
708 709 710 711
  void GenerateLoadInterceptor(Register holder_reg,
                               Handle<JSObject> object,
                               Handle<JSObject> holder,
                               LookupResult* lookup,
712
                               Handle<Name> name);
713 714
  void GenerateLoadPostInterceptor(Register reg,
                                   Handle<JSObject> interceptor_holder,
715
                                   Handle<Name> name,
716 717
                                   LookupResult* lookup);

718 719 720 721 722
  virtual Register receiver() { return registers_[0]; }
  virtual Register name()     { return registers_[1]; }
  virtual Register scratch1() { return registers_[2]; }
  virtual Register scratch2() { return registers_[3]; }
  virtual Register scratch3() { return registers_[4]; }
723 724 725 726
  Register scratch4() { return registers_[5]; }
};


727
class KeyedLoadStubCompiler: public LoadStubCompiler {
728
 public:
729
  explicit KeyedLoadStubCompiler(Isolate* isolate)
730
      : LoadStubCompiler(isolate, Code::KEYED_LOAD_IC) { }
731

732 733
  Handle<Code> CompileLoadElement(Handle<Map> receiver_map);

734 735
  void CompileElementHandlers(MapHandleList* receiver_maps,
                              CodeHandleList* handlers);
736

737 738
  static void GenerateLoadDictionaryElement(MacroAssembler* masm);

739
 protected:
740
  static Register* registers();
741 742

 private:
743
  virtual void GenerateNameCheck(Handle<Name> name,
744 745
                                 Register name_reg,
                                 Label* miss);
746
  friend class BaseLoadStoreStubCompiler;
747 748 749
};


750
class StoreStubCompiler: public BaseLoadStoreStubCompiler {
751
 public:
752 753 754 755
  StoreStubCompiler(Isolate* isolate,
                    StrictModeFlag strict_mode,
                    Code::Kind kind = Code::STORE_IC)
      : BaseLoadStoreStubCompiler(isolate, kind),
756
        strict_mode_(strict_mode) { }
757

758
  virtual ~StoreStubCompiler() { }
759

760 761 762 763 764
  Handle<Code> CompileStoreTransition(Handle<JSObject> object,
                                      LookupResult* lookup,
                                      Handle<Map> transition,
                                      Handle<Name> name);

765
  Handle<Code> CompileStoreField(Handle<JSObject> object,
766
                                 LookupResult* lookup,
767
                                 Handle<Name> name);
768

769 770 771 772 773
  void GenerateNegativeHolderLookup(MacroAssembler* masm,
                                    Handle<JSObject> holder,
                                    Register holder_reg,
                                    Handle<Name> name,
                                    Label* miss);
774

775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
  void GenerateStoreTransition(MacroAssembler* masm,
                               Handle<JSObject> object,
                               LookupResult* lookup,
                               Handle<Map> transition,
                               Handle<Name> name,
                               Register receiver_reg,
                               Register name_reg,
                               Register value_reg,
                               Register scratch1,
                               Register scratch2,
                               Register scratch3,
                               Label* miss_label,
                               Label* slow);

  void GenerateStoreField(MacroAssembler* masm,
                          Handle<JSObject> object,
                          LookupResult* lookup,
                          Register receiver_reg,
                          Register name_reg,
                          Register value_reg,
                          Register scratch1,
                          Register scratch2,
                          Label* miss_label);

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
  Handle<Code> CompileStoreCallback(Handle<JSObject> object,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
                                    Handle<ExecutableAccessorInfo> callback);

  Handle<Code> CompileStoreCallback(Handle<JSObject> object,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
                                    const CallOptimization& call_optimization);

  static void GenerateStoreViaSetter(MacroAssembler* masm,
                                     Handle<JSFunction> setter);

  Handle<Code> CompileStoreViaSetter(Handle<JSObject> object,
                                     Handle<JSObject> holder,
                                     Handle<Name> name,
                                     Handle<JSFunction> setter);

  Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
                                       Handle<Name> name);

820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
  static Builtins::Name SlowBuiltin(Code::Kind kind) {
    switch (kind) {
      case Code::STORE_IC: return Builtins::kStoreIC_Slow;
      case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
      default: UNREACHABLE();
    }
    return Builtins::kStoreIC_Slow;
  }

 protected:
  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
                                         Register object_reg,
                                         Handle<JSObject> holder,
                                         Handle<Name> name,
                                         Label* miss);

  virtual void HandlerFrontendFooter(Handle<Name> name,
                                     Label* success,
                                     Label* miss);
839 840 841 842
  void GenerateRestoreName(MacroAssembler* masm,
                           Label* label,
                           Handle<Name> name);

843 844
  virtual Register receiver() { return registers_[0]; }
  virtual Register name()     { return registers_[1]; }
845
  Register value()    { return registers_[2]; }
846 847 848
  virtual Register scratch1() { return registers_[3]; }
  virtual Register scratch2() { return registers_[4]; }
  virtual Register scratch3() { return registers_[5]; }
849 850 851
  StrictModeFlag strict_mode() { return strict_mode_; }
  virtual Code::ExtraICState extra_state() { return strict_mode_; }

852 853
 protected:
  static Register* registers();
854

855
 private:
856 857
  StrictModeFlag strict_mode_;
  friend class BaseLoadStoreStubCompiler;
858 859 860
};


861
class KeyedStoreStubCompiler: public StoreStubCompiler {
862
 public:
863 864
  KeyedStoreStubCompiler(Isolate* isolate,
                         StrictModeFlag strict_mode,
865
                         KeyedAccessStoreMode store_mode)
866
      : StoreStubCompiler(isolate, strict_mode, Code::KEYED_STORE_IC),
867
        store_mode_(store_mode) { }
868

869 870 871 872 873 874
  Handle<Code> CompileStoreElement(Handle<Map> receiver_map);

  Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps,
                                       CodeHandleList* handler_stubs,
                                       MapHandleList* transitioned_maps);

875 876
  Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);

877 878
  static void GenerateStoreDictionaryElement(MacroAssembler* masm);

879 880 881 882
 protected:
  virtual Code::ExtraICState extra_state() {
    return Code::ComputeExtraICState(store_mode_, strict_mode());
  }
883
  static Register* registers();
884

885
 private:
886 887 888 889
  Register transition_map() {
    return registers()[3];
  }

890 891 892
  virtual void GenerateNameCheck(Handle<Name> name,
                                 Register name_reg,
                                 Label* miss);
893
  KeyedAccessStoreMode store_mode_;
894
  friend class BaseLoadStoreStubCompiler;
895 896 897
};


898 899 900 901 902 903 904 905 906
// Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call
// IC stubs.
#define CUSTOM_CALL_IC_GENERATORS(V)            \
  V(ArrayPush)                                  \
  V(ArrayPop)                                   \
  V(StringCharCodeAt)                           \
  V(StringCharAt)                               \
  V(StringFromCharCode)                         \
  V(MathFloor)                                  \
907 908 909 910 911 912
  V(MathAbs)                                    \
  V(ArrayCode)


#define SITE_SPECIFIC_CALL_GENERATORS(V)        \
  V(ArrayCode)
913 914


915 916
class CallStubCompiler: public StubCompiler {
 public:
917 918
  CallStubCompiler(Isolate* isolate,
                   int argc,
919
                   Code::Kind kind,
920
                   Code::ExtraICState extra_state,
921
                   InlineCacheHolderFlag cache_holder = OWN_MAP);
922

923 924
  Handle<Code> CompileCallField(Handle<JSObject> object,
                                Handle<JSObject> holder,
925
                                PropertyIndex index,
926
                                Handle<Name> name);
927

928 929
  void CompileHandlerFrontend(Handle<Object> object,
                              Handle<JSObject> holder,
930
                              Handle<Name> name,
931 932 933 934 935
                              CheckType check,
                              Label* success);

  void CompileHandlerBackend(Handle<JSFunction> function);

936 937
  Handle<Code> CompileCallConstant(Handle<Object> object,
                                   Handle<JSObject> holder,
938
                                   Handle<Name> name,
939 940
                                   CheckType check,
                                   Handle<JSFunction> function);
941

942 943
  Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
                                      Handle<JSObject> holder,
944
                                      Handle<Name> name);
945 946 947

  Handle<Code> CompileCallGlobal(Handle<JSObject> object,
                                 Handle<GlobalObject> holder,
948
                                 Handle<PropertyCell> cell,
949
                                 Handle<JSFunction> function,
950
                                 Handle<Name> name);
951

952
  static bool HasCustomCallGenerator(Handle<JSFunction> function);
953
  static bool CanBeCached(Handle<JSFunction> function);
954 955

 private:
956 957 958 959 960
  // Compiles a custom call constant/global IC.  For constant calls cell is
  // NULL.  Returns an empty handle if there is no custom call code for the
  // given function.
  Handle<Code> CompileCustomCall(Handle<Object> object,
                                 Handle<JSObject> holder,
961
                                 Handle<Cell> cell,
962
                                 Handle<JSFunction> function,
963 964
                                 Handle<String> name,
                                 Code::StubType type);
965 966 967 968

#define DECLARE_CALL_GENERATOR(name)                                    \
  Handle<Code> Compile##name##Call(Handle<Object> object,               \
                                   Handle<JSObject> holder,             \
969
                                   Handle<Cell> cell,                   \
970
                                   Handle<JSFunction> function,         \
971 972
                                   Handle<String> fname,                \
                                   Code::StubType type);
973 974
  CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
#undef DECLARE_CALL_GENERATOR
975

976 977 978
  Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
                                  Handle<Object> object,
                                  Handle<JSObject> holder,
979
                                  Handle<Cell> cell,
980 981
                                  Handle<JSFunction> function,
                                  Handle<String> name);
982

983
  Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
984
  Handle<Code> GetCode(Handle<JSFunction> function);
985

986
  const ParameterCount& arguments() { return arguments_; }
987

988
  void GenerateNameCheck(Handle<Name> name, Label* miss);
989

990 991
  void GenerateGlobalReceiverCheck(Handle<JSObject> object,
                                   Handle<JSObject> holder,
992
                                   Handle<Name> name,
993 994 995 996
                                   Label* miss);

  // Generates code to load the function from the cell checking that
  // it still contains the same function.
997
  void GenerateLoadFunctionFromCell(Handle<Cell> cell,
998
                                    Handle<JSFunction> function,
999 1000
                                    Label* miss);

1001 1002 1003
  // Generates a jump to CallIC miss stub.
  void GenerateMissBranch();

1004 1005 1006 1007
  const ParameterCount arguments_;
  const Code::Kind kind_;
  const Code::ExtraICState extra_state_;
  const InlineCacheHolderFlag cache_holder_;
1008 1009 1010
};


1011 1012 1013 1014 1015
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
 public:
  explicit CallOptimization(LookupResult* lookup);

1016
  explicit CallOptimization(Handle<JSFunction> function);
1017 1018

  bool is_constant_call() const {
1019
    return !constant_function_.is_null();
1020 1021
  }

1022 1023
  Handle<JSFunction> constant_function() const {
    ASSERT(is_constant_call());
1024 1025 1026 1027 1028 1029 1030
    return constant_function_;
  }

  bool is_simple_api_call() const {
    return is_simple_api_call_;
  }

1031 1032
  Handle<FunctionTemplateInfo> expected_receiver_type() const {
    ASSERT(is_simple_api_call());
1033 1034 1035
    return expected_receiver_type_;
  }

1036 1037
  Handle<CallHandlerInfo> api_call_info() const {
    ASSERT(is_simple_api_call());
1038 1039 1040 1041 1042
    return api_call_info_;
  }

  // Returns the depth of the object having the expected type in the
  // prototype chain between the two arguments.
1043 1044
  int GetPrototypeDepthOfExpectedType(Handle<JSObject> object,
                                      Handle<JSObject> holder) const;
1045

1046 1047 1048 1049 1050 1051
  bool IsCompatibleReceiver(Object* receiver) {
    ASSERT(is_simple_api_call());
    if (expected_receiver_type_.is_null()) return true;
    return receiver->IsInstanceOf(*expected_receiver_type_);
  }

1052
 private:
1053
  void Initialize(Handle<JSFunction> function);
1054 1055 1056

  // Determines whether the given function can be called using the
  // fast api call builtin.
1057
  void AnalyzePossibleApiFunction(Handle<JSFunction> function);
1058

1059
  Handle<JSFunction> constant_function_;
1060
  bool is_simple_api_call_;
1061 1062
  Handle<FunctionTemplateInfo> expected_receiver_type_;
  Handle<CallHandlerInfo> api_call_info_;
1063 1064
};

danno@chromium.org's avatar
danno@chromium.org committed
1065

1066 1067 1068
} }  // namespace v8::internal

#endif  // V8_STUB_CACHE_H_