stub-cache.h 44.5 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
class SmallMapList;
52 53
class StubCache;

54

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

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

  Address address_;

  friend class StubCache;
};
66

67

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

76
  void Initialize();
77

78 79 80
  Handle<JSObject> StubHolder(Handle<JSObject> receiver,
                              Handle<JSObject> holder);

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

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

93 94
  Handle<Code> FindHandler(
      Handle<Name> name,
95
      Handle<JSObject> receiver,
96 97
      Handle<JSObject> stub_holder,
      Code::Kind kind,
98
      Code::StubType type);
99 100 101

  Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
                                    Handle<Code> handler,
102
                                    Handle<Name> name);
103 104
  Handle<Code> ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
                                         Handle<Code> handler,
105
                                         Handle<Name> name);
106 107 108

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

112
  Handle<Code> ComputeLoadField(Handle<Name> name,
113
                                Handle<JSObject> object,
114
                                Handle<JSObject> holder,
115
                                PropertyIndex field_index);
116

117
  Handle<Code> ComputeLoadCallback(Handle<Name> name,
118
                                   Handle<JSObject> object,
119
                                   Handle<JSObject> holder,
120
                                   Handle<ExecutableAccessorInfo> callback);
121

122
  Handle<Code> ComputeLoadViaGetter(Handle<Name> name,
123
                                    Handle<JSObject> object,
124 125 126
                                    Handle<JSObject> holder,
                                    Handle<JSFunction> getter);

127
  Handle<Code> ComputeLoadConstant(Handle<Name> name,
128
                                   Handle<JSObject> object,
129
                                   Handle<JSObject> holder,
130
                                   Handle<JSFunction> value);
131

132
  Handle<Code> ComputeLoadInterceptor(Handle<Name> name,
133
                                      Handle<JSObject> object,
134
                                      Handle<JSObject> holder);
135

136
  Handle<Code> ComputeLoadNormal(Handle<Name> name,
137
                                 Handle<JSObject> object);
138

139
  Handle<Code> ComputeLoadGlobal(Handle<Name> name,
140
                                 Handle<JSObject> object,
141 142 143
                                 Handle<GlobalObject> holder,
                                 Handle<JSGlobalPropertyCell> cell,
                                 bool is_dont_delete);
144 145 146

  // ---

147
  Handle<Code> ComputeKeyedLoadField(Handle<Name> name,
148
                                     Handle<JSObject> object,
149
                                     Handle<JSObject> holder,
150
                                     PropertyIndex field_index);
151

152
  Handle<Code> ComputeKeyedLoadCallback(
153
      Handle<Name> name,
154 155 156
      Handle<JSObject> object,
      Handle<JSObject> holder,
      Handle<ExecutableAccessorInfo> callback);
157

158
  Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name,
159
                                        Handle<JSObject> object,
160
                                        Handle<JSObject> holder,
161
                                        Handle<JSFunction> value);
162

163
  Handle<Code> ComputeKeyedLoadInterceptor(Handle<Name> name,
164
                                           Handle<JSObject> object,
165
                                           Handle<JSObject> holder);
166

167 168
  // ---

169
  Handle<Code> ComputeStoreField(Handle<Name> name,
170
                                 Handle<JSObject> object,
171
                                 LookupResult* lookup,
172
                                 StrictModeFlag strict_mode);
173

174 175 176 177 178 179
  Handle<Code> ComputeStoreTransition(Handle<Name> name,
                                      Handle<JSObject> object,
                                      LookupResult* lookup,
                                      Handle<Map> transition,
                                      StrictModeFlag strict_mode);

180
  Handle<Code> ComputeStoreNormal(StrictModeFlag strict_mode);
181

182
  Handle<Code> ComputeStoreGlobal(Handle<Name> name,
183
                                  Handle<GlobalObject> object,
184 185
                                  Handle<JSGlobalPropertyCell> cell,
                                  StrictModeFlag strict_mode);
186

187
  Handle<Code> ComputeStoreCallback(Handle<Name> name,
188
                                    Handle<JSObject> object,
189
                                    Handle<JSObject> holder,
190
                                    Handle<ExecutableAccessorInfo> callback,
191
                                    StrictModeFlag strict_mode);
192

193
  Handle<Code> ComputeStoreViaSetter(Handle<Name> name,
194
                                     Handle<JSObject> object,
195
                                     Handle<JSObject> holder,
196 197 198
                                     Handle<JSFunction> setter,
                                     StrictModeFlag strict_mode);

199
  Handle<Code> ComputeStoreInterceptor(Handle<Name> name,
200
                                       Handle<JSObject> object,
201
                                       StrictModeFlag strict_mode);
202

203 204
  // ---

205
  Handle<Code> ComputeKeyedStoreField(Handle<Name> name,
206
                                      Handle<JSObject> object,
207
                                      LookupResult* lookup,
208
                                      StrictModeFlag strict_mode);
209 210 211 212 213
  Handle<Code> ComputeKeyedStoreTransition(Handle<Name> name,
                                           Handle<JSObject> object,
                                           LookupResult* lookup,
                                           Handle<Map> transition,
                                           StrictModeFlag strict_mode);
214

215 216 217 218
  Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);

  Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
                                        StrictModeFlag strict_mode,
219
                                        KeyedAccessStoreMode store_mode);
220

221 222
  // ---

223 224 225
  Handle<Code> ComputeCallField(int argc,
                                Code::Kind,
                                Code::ExtraICState extra_state,
226
                                Handle<Name> name,
227 228
                                Handle<Object> object,
                                Handle<JSObject> holder,
229
                                PropertyIndex index);
230

231 232 233
  Handle<Code> ComputeCallConstant(int argc,
                                   Code::Kind,
                                   Code::ExtraICState extra_state,
234
                                   Handle<Name> name,
235 236 237
                                   Handle<Object> object,
                                   Handle<JSObject> holder,
                                   Handle<JSFunction> function);
238

239 240 241
  Handle<Code> ComputeCallInterceptor(int argc,
                                      Code::Kind,
                                      Code::ExtraICState extra_state,
242
                                      Handle<Name> name,
243 244
                                      Handle<Object> object,
                                      Handle<JSObject> holder);
245

246 247 248
  Handle<Code> ComputeCallGlobal(int argc,
                                 Code::Kind,
                                 Code::ExtraICState extra_state,
249
                                 Handle<Name> name,
250
                                 Handle<JSObject> object,
251 252 253
                                 Handle<GlobalObject> holder,
                                 Handle<JSGlobalPropertyCell> cell,
                                 Handle<JSFunction> function);
254

255
  // ---
256

257
  Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
258

259
  Handle<Code> ComputeKeyedCallInitialize(int argc);
260

261 262 263 264 265 266 267
  Handle<Code> ComputeCallPreMonomorphic(int argc,
                                         Code::Kind kind,
                                         Code::ExtraICState extra_state);

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

269
  Handle<Code> ComputeCallArguments(int argc);
270

271 272 273
  Handle<Code> ComputeCallMegamorphic(int argc,
                                      Code::Kind kind,
                                      Code::ExtraICState state);
274

275 276 277
  Handle<Code> ComputeCallMiss(int argc,
                               Code::Kind kind,
                               Code::ExtraICState state);
278

279 280
  // ---

281 282 283 284 285 286
  Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
                                 NilValue nil,
                                 CompareNilICStub::Types types);

  // ---

287 288
  Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
  Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
289
                                              KeyedAccessStoreMode store_mode,
290 291
                                              StrictModeFlag strict_mode);

292 293
  Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
                                    CodeHandleList* handlers,
294
                                    Handle<Name> name);
295

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

299
#ifdef ENABLE_DEBUGGER_SUPPORT
300
  Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
301

302
  Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
303
#endif
304 305

  // Update cache for entry hash(name, map).
306
  Code* Set(Name* name, Map* map, Code* code);
307 308

  // Clear the lookup table (@ mark compact collection).
309
  void Clear();
310

311
  // Collect all maps that match the name and flags.
312
  void CollectMatchingMaps(SmallMapList* types,
313
                           Name* name,
314
                           Code::Flags flags,
315
                           Handle<Context> native_context,
316
                           Zone* zone);
317

318
  // Generate code for probing the stub cache table.
319
  // Arguments extra, extra2 and extra3 may be used to pass additional scratch
320
  // registers. Set to no_reg if not needed.
321 322 323 324 325 326
  void GenerateProbe(MacroAssembler* masm,
                     Code::Flags flags,
                     Register receiver,
                     Register name,
                     Register scratch,
                     Register extra,
327 328
                     Register extra2 = no_reg,
                     Register extra3 = no_reg);
329 330 331 332 333 334

  enum Table {
    kPrimary,
    kSecondary
  };

335 336 337 338 339 340 341

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


342 343 344 345 346 347
  SCTableReference map_reference(StubCache::Table table) {
    return SCTableReference(
        reinterpret_cast<Address>(&first_entry(table)->map));
  }


348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
  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;
  }

363
  Isolate* isolate() { return isolate_; }
ager@chromium.org's avatar
ager@chromium.org committed
364
  Heap* heap() { return isolate()->heap(); }
365
  Factory* factory() { return isolate()->factory(); }
366

367
 private:
368
  StubCache(Isolate* isolate, Zone* zone);
369

370 371 372
  Handle<Code> ComputeCallInitialize(int argc,
                                     RelocInfo::Mode mode,
                                     Code::Kind kind);
373

374 375 376 377 378 379 380 381 382 383
  // 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.
384
  static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
385 386 387 388
    // 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.
389
    STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
390
    // Compute the hash of the name (use entire hash field).
391
    ASSERT(name->HasHashCode());
392
    uint32_t field = name->hash_field();
393 394 395 396 397
    // 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));
398 399 400 401
    // 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);
402
    // Base the offset on a simple combination of name, flags, and map.
403
    uint32_t key = (map_low32bits + field) ^ iflags;
404 405 406
    return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
  }

407 408 409
  // 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.
410
  static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
411
    // Use the seed from the primary cache in the secondary cache.
412
    uint32_t name_low32bits =
413
        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
414 415 416 417
    // 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);
418
    uint32_t key = (seed - name_low32bits) + iflags;
419 420 421 422
    return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
  }

  // Compute the entry for a given offset in exactly the same way as
423
  // we do in generated code.  We generate an hash code that already
424
  // ends in Name::kHashShift 0s.  Then we multiply it so it is a multiple
425 426
  // of sizeof(Entry).  This makes it easier to avoid making mistakes
  // in the hashed offset computations.
427
  static Entry* entry(Entry* table, int offset) {
428
    const int multiplier = sizeof(*table) >> Name::kHashShift;
429
    return reinterpret_cast<Entry*>(
430
        reinterpret_cast<Address>(table) + offset * multiplier);
431
  }
432

433 434 435 436
  static const int kPrimaryTableBits = 11;
  static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
  static const int kSecondaryTableBits = 9;
  static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
437 438 439

  Entry primary_[kPrimaryTableSize];
  Entry secondary_[kSecondaryTableSize];
440
  Isolate* isolate_;
441

442 443 444
  friend class Isolate;
  friend class SCTableReference;

445
  DISALLOW_COPY_AND_ASSIGN(StubCache);
446
};
447

448

449 450 451 452
// ------------------------------------------------------------------------


// Support functions for IC stubs for callbacks.
453
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty);
454 455 456


// Support functions for IC stubs for interceptors.
457 458 459 460 461 462
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);
463 464


465 466 467 468
enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
enum IcCheckType { ELEMENT, PROPERTY };


469
// The stub compilers compile stubs for the stub cache.
470 471
class StubCompiler BASE_EMBEDDED {
 public:
472 473
  explicit StubCompiler(Isolate* isolate)
      : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { }
474

475 476
  // Functions to compile either CallIC or KeyedCallIC.  The specific kind
  // is extracted from the code flags.
477 478 479 480 481 482
  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);
483

484
#ifdef ENABLE_DEBUGGER_SUPPORT
485 486
  Handle<Code> CompileCallDebugBreak(Code::Flags flags);
  Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags);
487
#endif
488 489 490 491 492

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

494
  // Generates prototype loading code that uses the objects from the
495 496 497 498 499
  // 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.
500 501
  static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
                                                        int index,
502 503
                                                        Register prototype,
                                                        Label* miss);
504

505
  static void GenerateFastPropertyLoad(MacroAssembler* masm,
506 507 508
                                       Register dst,
                                       Register src,
                                       Handle<JSObject> holder,
509
                                       PropertyIndex index);
510 511 512 513 514
  static void DoGenerateFastPropertyLoad(MacroAssembler* masm,
                                         Register dst,
                                         Register src,
                                         bool inobject,
                                         int index);
515

516 517 518 519
  static void GenerateLoadArrayLength(MacroAssembler* masm,
                                      Register receiver,
                                      Register scratch,
                                      Label* miss_label);
520

521
  static void GenerateLoadStringLength(MacroAssembler* masm,
522 523 524
                                       Register receiver,
                                       Register scratch1,
                                       Register scratch2,
525 526
                                       Label* miss_label,
                                       bool support_wrappers);
527

528 529 530 531 532
  static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
                                            Register receiver,
                                            Register scratch1,
                                            Register scratch2,
                                            Label* miss_label);
533

534 535 536 537 538 539 540 541 542 543 544 545 546
  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,
                               Label* miss_label,
                               Label* miss_restore_name);

547 548
  void GenerateStoreField(MacroAssembler* masm,
                          Handle<JSObject> object,
549
                          LookupResult* lookup,
550 551
                          Register receiver_reg,
                          Register name_reg,
552
                          Register value_reg,
553 554
                          Register scratch1,
                          Register scratch2,
555
                          Label* miss_label);
556 557 558 559 560 561 562 563 564 565 566 567

  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;
  }
  static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
568

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
  // 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].
584 585 586 587 588 589
  Register CheckPrototypes(Handle<JSObject> object,
                           Register object_reg,
                           Handle<JSObject> holder,
                           Register holder_reg,
                           Register scratch1,
                           Register scratch2,
590
                           Handle<Name> name,
591 592
                           Label* miss,
                           PrototypeCheckType check = CHECK_ALL_MAPS) {
593
    return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
594
                           scratch2, name, kInvalidProtoDepth, miss, check);
595
  }
596

597 598 599 600 601 602
  Register CheckPrototypes(Handle<JSObject> object,
                           Register object_reg,
                           Handle<JSObject> holder,
                           Register holder_reg,
                           Register scratch1,
                           Register scratch2,
603
                           Handle<Name> name,
604
                           int save_at_depth,
605 606
                           Label* miss,
                           PrototypeCheckType check = CHECK_ALL_MAPS);
607

608

609
 protected:
610
  Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
611
  Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
612

613 614 615
  MacroAssembler* masm() { return &masm_; }
  void set_failure(Failure* failure) { failure_ = failure; }

616
  static void LookupPostInterceptor(Handle<JSObject> holder,
617
                                    Handle<Name> name,
618 619
                                    LookupResult* lookup);

620
  Isolate* isolate() { return isolate_; }
621 622
  Heap* heap() { return isolate()->heap(); }
  Factory* factory() { return isolate()->factory(); }
623

624
  static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
625

626
 private:
627
  Isolate* isolate_;
628
  MacroAssembler masm_;
629
  Failure* failure_;
630 631 632
};


633 634 635
enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };


636
class BaseLoadStubCompiler: public StubCompiler {
637
 public:
638 639 640
  BaseLoadStubCompiler(Isolate* isolate, Register* registers)
      : StubCompiler(isolate), registers_(registers) { }
  virtual ~BaseLoadStubCompiler() { }
641 642 643

  Handle<Code> CompileLoadField(Handle<JSObject> object,
                                Handle<JSObject> holder,
644
                                Handle<Name> name,
645
                                PropertyIndex index);
646

647
  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
648
                                   Handle<JSObject> holder,
649
                                   Handle<Name> name,
650
                                   Handle<ExecutableAccessorInfo> callback);
651 652 653

  Handle<Code> CompileLoadConstant(Handle<JSObject> object,
                                   Handle<JSObject> holder,
654
                                   Handle<Name> name,
655
                                   Handle<JSFunction> value);
656 657 658

  Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
                                      Handle<JSObject> holder,
659
                                      Handle<Name> name);
660

661 662
  Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
                                    Handle<Code> handler,
663
                                    Handle<Name> name);
664 665
  Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
                                    CodeHandleList* handlers,
666
                                    Handle<Name> name,
667 668 669
                                    Code::StubType type,
                                    IcCheckType check);

670
 protected:
671 672 673
  Register HandlerFrontendHeader(Handle<JSObject> object,
                                 Register object_reg,
                                 Handle<JSObject> holder,
674
                                 Handle<Name> name,
675
                                 Label* success);
676 677 678 679 680
  void HandlerFrontendFooter(Label* success, Label* miss);

  Register HandlerFrontend(Handle<JSObject> object,
                           Register object_reg,
                           Handle<JSObject> holder,
681
                           Handle<Name> name,
682
                           Label* success);
683 684 685
  Register CallbackHandlerFrontend(Handle<JSObject> object,
                                   Register object_reg,
                                   Handle<JSObject> holder,
686
                                   Handle<Name> name,
687 688 689 690
                                   Label* success,
                                   Handle<ExecutableAccessorInfo> callback);
  void NonexistentHandlerFrontend(Handle<JSObject> object,
                                  Handle<JSObject> last,
691
                                  Handle<Name> name,
692 693 694 695 696 697 698 699 700 701 702 703 704
                                  Label* success,
                                  Handle<GlobalObject> global);

  void GenerateLoadField(Register reg,
                         Handle<JSObject> holder,
                         PropertyIndex index);
  void GenerateLoadConstant(Handle<JSFunction> value);
  void GenerateLoadCallback(Register reg,
                            Handle<ExecutableAccessorInfo> callback);
  void GenerateLoadInterceptor(Register holder_reg,
                               Handle<JSObject> object,
                               Handle<JSObject> holder,
                               LookupResult* lookup,
705
                               Handle<Name> name);
706 707
  void GenerateLoadPostInterceptor(Register reg,
                                   Handle<JSObject> interceptor_holder,
708
                                   Handle<Name> name,
709 710
                                   LookupResult* lookup);

711 712 713 714 715 716
  Handle<Code> GetICCode(Code::Kind kind,
                         Code::StubType type,
                         Handle<Name> name,
                         InlineCacheState state = MONOMORPHIC);

  Handle<Code> GetCode(Code::Kind kind,
717
                       Code::StubType type,
718
                       Handle<Name> name);
719

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

 private:
  virtual Code::Kind kind() = 0;
729
  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
730 731
  virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0;
  virtual void GenerateNameCheck(Handle<Name> name,
732 733 734 735 736 737 738 739 740 741 742 743 744
                                 Register name_reg,
                                 Label* miss) { }
  Register* registers_;
};


class LoadStubCompiler: public BaseLoadStubCompiler {
 public:
  explicit LoadStubCompiler(Isolate* isolate)
      : BaseLoadStubCompiler(isolate, registers()) { }

  Handle<Code> CompileLoadNonexistent(Handle<JSObject> object,
                                      Handle<JSObject> last,
745
                                      Handle<Name> name,
746 747 748 749 750 751 752
                                      Handle<GlobalObject> global);

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

  Handle<Code> CompileLoadViaGetter(Handle<JSObject> object,
                                    Handle<JSObject> holder,
753
                                    Handle<Name> name,
754 755
                                    Handle<JSFunction> getter);

756 757 758
  Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
                                 Handle<GlobalObject> holder,
                                 Handle<JSGlobalPropertyCell> cell,
759
                                 Handle<Name> name,
760 761
                                 bool is_dont_delete);

762 763
  static Register receiver() { return registers()[0]; }

764
 private:
765
  static Register* registers();
766
  virtual Code::Kind kind() { return Code::LOAD_IC; }
767
  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
768
    if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
769 770 771
    return code->ic_state() == MONOMORPHIC
        ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
  }
772
  virtual void JitEvent(Handle<Name> name, Handle<Code> code);
773 774 775
};


776
class KeyedLoadStubCompiler: public BaseLoadStubCompiler {
777
 public:
778 779
  explicit KeyedLoadStubCompiler(Isolate* isolate)
      : BaseLoadStubCompiler(isolate, registers()) { }
780

781 782
  Handle<Code> CompileLoadElement(Handle<Map> receiver_map);

783 784
  void CompileElementHandlers(MapHandleList* receiver_maps,
                              CodeHandleList* handlers);
785

786 787
  static void GenerateLoadDictionaryElement(MacroAssembler* masm);

788 789
  static Register receiver() { return registers()[0]; }

790
 private:
791
  static Register* registers();
792
  virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; }
793
  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
794
    if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
795 796 797
    return code->ic_state() == MONOMORPHIC
        ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
  }
798 799
  virtual void JitEvent(Handle<Name> name, Handle<Code> code);
  virtual void GenerateNameCheck(Handle<Name> name,
800 801
                                 Register name_reg,
                                 Label* miss);
802 803 804
};


805
class BaseStoreStubCompiler: public StubCompiler {
806
 public:
807 808 809 810 811 812
  BaseStoreStubCompiler(Isolate* isolate,
                        StrictModeFlag strict_mode,
                        Register* registers)
      : StubCompiler(isolate),
        strict_mode_(strict_mode),
        registers_(registers) { }
813

814
  virtual ~BaseStoreStubCompiler() { }
815

816 817 818 819 820
  Handle<Code> CompileStoreTransition(Handle<JSObject> object,
                                      LookupResult* lookup,
                                      Handle<Map> transition,
                                      Handle<Name> name);

821
  Handle<Code> CompileStoreField(Handle<JSObject> object,
822
                                 LookupResult* lookup,
823
                                 Handle<Name> name);
824

825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
 protected:
  Handle<Code> GetICCode(Code::Kind kind,
                         Code::StubType type,
                         Handle<Name> name,
                         InlineCacheState state = MONOMORPHIC);

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

  void GenerateRestoreName(MacroAssembler* masm,
                           Label* label,
                           Handle<Name> name);

  Register receiver() { return registers_[0]; }
  Register name()     { return registers_[1]; }
  Register value()    { return registers_[2]; }
  Register scratch1() { return registers_[3]; }
  Register scratch2() { return registers_[4]; }
  Register scratch3() { return registers_[5]; }
  StrictModeFlag strict_mode() { return strict_mode_; }
  virtual Code::ExtraICState extra_state() { return strict_mode_; }

 private:
  virtual Code::Kind kind() = 0;
  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
  virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0;
  virtual void GenerateNameCheck(Handle<Name> name,
                                 Register name_reg,
                                 Label* miss) { }
  StrictModeFlag strict_mode_;
  Register* registers_;
};


class StoreStubCompiler: public BaseStoreStubCompiler {
 public:
  StoreStubCompiler(Isolate* isolate, StrictModeFlag strict_mode)
      : BaseStoreStubCompiler(isolate, strict_mode, registers()) { }


866
  Handle<Code> CompileStoreCallback(Handle<Name> name,
867
                                    Handle<JSObject> object,
868
                                    Handle<JSObject> holder,
869
                                    Handle<ExecutableAccessorInfo> callback);
870

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

874
  Handle<Code> CompileStoreViaSetter(Handle<Name> name,
875
                                     Handle<JSObject> object,
876 877
                                     Handle<JSObject> holder,
                                     Handle<JSFunction> setter);
878

879
  Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
880
                                       Handle<Name> name);
881 882 883

  Handle<Code> CompileStoreGlobal(Handle<GlobalObject> object,
                                  Handle<JSGlobalPropertyCell> holder,
884
                                  Handle<Name> name);
885

886
 private:
887 888 889 890 891 892 893 894
  static Register* registers();
  virtual Code::Kind kind() { return Code::STORE_IC; }
  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
    if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
    return code->ic_state() == MONOMORPHIC
        ? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG;
  }
  virtual void JitEvent(Handle<Name> name, Handle<Code> code);
895 896 897
};


898
class KeyedStoreStubCompiler: public BaseStoreStubCompiler {
899
 public:
900 901
  KeyedStoreStubCompiler(Isolate* isolate,
                         StrictModeFlag strict_mode,
902
                         KeyedAccessStoreMode store_mode)
903 904
      : BaseStoreStubCompiler(isolate, strict_mode, registers()),
        store_mode_(store_mode) { }
905

906 907 908 909 910 911
  Handle<Code> CompileStoreElement(Handle<Map> receiver_map);

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

912 913
  Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);

danno@chromium.org's avatar
danno@chromium.org committed
914
  static void GenerateStoreFastElement(MacroAssembler* masm,
915
                                       bool is_js_array,
916
                                       ElementsKind element_kind,
917
                                       KeyedAccessStoreMode store_mode);
danno@chromium.org's avatar
danno@chromium.org committed
918

919
  static void GenerateStoreFastDoubleElement(MacroAssembler* masm,
920
                                             bool is_js_array,
921
                                             KeyedAccessStoreMode store_mode);
922

danno@chromium.org's avatar
danno@chromium.org committed
923
  static void GenerateStoreExternalArray(MacroAssembler* masm,
924
                                         ElementsKind elements_kind);
925

926 927
  static void GenerateStoreDictionaryElement(MacroAssembler* masm);

928 929 930 931
 protected:
  virtual Code::ExtraICState extra_state() {
    return Code::ComputeExtraICState(store_mode_, strict_mode());
  }
932

933
 private:
934 935 936 937
  Register transition_map() {
    return registers()[3];
  }

938 939 940 941 942 943 944 945 946 947 948
  static Register* registers();
  virtual Code::Kind kind() { return Code::KEYED_STORE_IC; }
  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
    if (!code->is_inline_cache_stub()) return Logger::STUB_TAG;
    return code->ic_state() == MONOMORPHIC
        ? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG;
  }
  virtual void JitEvent(Handle<Name> name, Handle<Code> code);
  virtual void GenerateNameCheck(Handle<Name> name,
                                 Register name_reg,
                                 Label* miss);
949
  KeyedAccessStoreMode store_mode_;
950 951 952
};


953 954 955 956 957 958 959 960 961 962
// 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)                                  \
  V(MathAbs)
963 964


965 966
class CallOptimization;

967 968
class CallStubCompiler: public StubCompiler {
 public:
969 970
  CallStubCompiler(Isolate* isolate,
                   int argc,
971
                   Code::Kind kind,
972
                   Code::ExtraICState extra_state,
973
                   InlineCacheHolderFlag cache_holder);
974

975 976
  Handle<Code> CompileCallField(Handle<JSObject> object,
                                Handle<JSObject> holder,
977
                                PropertyIndex index,
978
                                Handle<Name> name);
979

980 981
  void CompileHandlerFrontend(Handle<Object> object,
                              Handle<JSObject> holder,
982
                              Handle<Name> name,
983 984 985 986 987
                              CheckType check,
                              Label* success);

  void CompileHandlerBackend(Handle<JSFunction> function);

988 989
  Handle<Code> CompileCallConstant(Handle<Object> object,
                                   Handle<JSObject> holder,
990
                                   Handle<Name> name,
991 992
                                   CheckType check,
                                   Handle<JSFunction> function);
993

994 995
  Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
                                      Handle<JSObject> holder,
996
                                      Handle<Name> name);
997 998 999 1000 1001

  Handle<Code> CompileCallGlobal(Handle<JSObject> object,
                                 Handle<GlobalObject> holder,
                                 Handle<JSGlobalPropertyCell> cell,
                                 Handle<JSFunction> function,
1002
                                 Handle<Name> name);
1003

1004
  static bool HasCustomCallGenerator(Handle<JSFunction> function);
1005 1006

 private:
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
  // 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,
                                 Handle<JSGlobalPropertyCell> cell,
                                 Handle<JSFunction> function,
                                 Handle<String> name);

#define DECLARE_CALL_GENERATOR(name)                                    \
  Handle<Code> Compile##name##Call(Handle<Object> object,               \
                                   Handle<JSObject> holder,             \
                                   Handle<JSGlobalPropertyCell> cell,   \
                                   Handle<JSFunction> function,         \
                                   Handle<String> fname);
1022 1023
  CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
#undef DECLARE_CALL_GENERATOR
1024

1025 1026 1027 1028 1029 1030
  Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
                                  Handle<Object> object,
                                  Handle<JSObject> holder,
                                  Handle<JSGlobalPropertyCell> cell,
                                  Handle<JSFunction> function,
                                  Handle<String> name);
1031

1032
  Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
1033
  Handle<Code> GetCode(Handle<JSFunction> function);
1034

1035
  const ParameterCount& arguments() { return arguments_; }
1036

1037
  void GenerateNameCheck(Handle<Name> name, Label* miss);
1038

1039 1040
  void GenerateGlobalReceiverCheck(Handle<JSObject> object,
                                   Handle<JSObject> holder,
1041
                                   Handle<Name> name,
1042 1043 1044 1045
                                   Label* miss);

  // Generates code to load the function from the cell checking that
  // it still contains the same function.
1046 1047
  void GenerateLoadFunctionFromCell(Handle<JSGlobalPropertyCell> cell,
                                    Handle<JSFunction> function,
1048 1049
                                    Label* miss);

1050 1051 1052
  // Generates a jump to CallIC miss stub.
  void GenerateMissBranch();

1053 1054 1055 1056
  const ParameterCount arguments_;
  const Code::Kind kind_;
  const Code::ExtraICState extra_state_;
  const InlineCacheHolderFlag cache_holder_;
1057 1058 1059
};


1060 1061
class ConstructStubCompiler: public StubCompiler {
 public:
1062
  explicit ConstructStubCompiler(Isolate* isolate) : StubCompiler(isolate) { }
1063

1064
  Handle<Code> CompileConstructStub(Handle<JSFunction> function);
1065 1066

 private:
1067
  Handle<Code> GetCode();
1068 1069 1070
};


1071 1072 1073 1074 1075
// Holds information about possible function call optimizations.
class CallOptimization BASE_EMBEDDED {
 public:
  explicit CallOptimization(LookupResult* lookup);

1076
  explicit CallOptimization(Handle<JSFunction> function);
1077 1078

  bool is_constant_call() const {
1079
    return !constant_function_.is_null();
1080 1081
  }

1082 1083
  Handle<JSFunction> constant_function() const {
    ASSERT(is_constant_call());
1084 1085 1086 1087 1088 1089 1090
    return constant_function_;
  }

  bool is_simple_api_call() const {
    return is_simple_api_call_;
  }

1091 1092
  Handle<FunctionTemplateInfo> expected_receiver_type() const {
    ASSERT(is_simple_api_call());
1093 1094 1095
    return expected_receiver_type_;
  }

1096 1097
  Handle<CallHandlerInfo> api_call_info() const {
    ASSERT(is_simple_api_call());
1098 1099 1100 1101 1102
    return api_call_info_;
  }

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

 private:
1107
  void Initialize(Handle<JSFunction> function);
1108 1109 1110

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

1113
  Handle<JSFunction> constant_function_;
1114
  bool is_simple_api_call_;
1115 1116
  Handle<FunctionTemplateInfo> expected_receiver_type_;
  Handle<CallHandlerInfo> api_call_info_;
1117 1118
};

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

1120 1121 1122
} }  // namespace v8::internal

#endif  // V8_STUB_CACHE_H_